diff options
274 files changed, 55693 insertions, 0 deletions
diff --git a/lib/csu/i386/Makefile b/lib/csu/i386/Makefile new file mode 100644 index 000000000000..dfaf29398119 --- /dev/null +++ b/lib/csu/i386/Makefile @@ -0,0 +1,25 @@ +#	@(#)Makefile	8.1 (Berkeley) 6/1/93 + +CFLAGS=	-O -DLIBC_SCCS +OBJS=	crt0.o gcrt0.o +CLEANFILES+=	core a.out + +all: ${OBJS} + +crt0.o: crt0.c +	${CC} ${CFLAGS} -c -DCRT0 ${.ALLSRC} +	${LD} -x -r ${.TARGET} +	mv a.out ${.TARGET} + +gcrt0.o: crt0.c +	${CC} ${CFLAGS} -c -DMCRT0 ${.ALLSRC} -o ${.TARGET} +	${LD} -x -r ${.TARGET} +	mv a.out ${.TARGET} + +install: +	install -o ${BINOWN} -g ${BINGRP} -m 444 ${OBJS} \ +	    ${DESTDIR}/usr/lib + +depend lint tags: + +.include <bsd.prog.mk> diff --git a/lib/csu/i386/crt0.c b/lib/csu/i386/crt0.c new file mode 100644 index 000000000000..77f9382d9909 --- /dev/null +++ b/lib/csu/i386/crt0.c @@ -0,0 +1,130 @@ +/*- + * Copyright (c) 1990, 1993 + *	The 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 sccsid[] = "@(#)crt0.c	8.1 (Berkeley) 6/1/93"; +#endif /* not lint */ + +/* + *	C start up routine. + *	Robert Henry, UCB, 20 Oct 81 + * + *	We make the following (true) assumption: + *	1) The only register variable that we can trust is ebp, + *	which points to the base of the kernel calling frame. + */ + +#include <stddef.h> +#include <stdlib.h> +#include <string.h> + +char **environ = (char **)0; +static char empty[1]; +char *__progname = empty; +static int fd; + +asm(".text"); +asm(".long 0xc000c000"); + +extern	unsigned char	etext; +extern	unsigned char	eprol asm ("eprol"); +extern			start() asm("start"); + +start() +{ +	struct kframe { +		int	kargc; +		char	*kargv[1];	/* size depends on kargc */ +		char	kargstr[1];	/* size varies */ +		char	kenvstr[1];	/* size varies */ +	}; +	/* +	 *	ALL REGISTER VARIABLES!!! +	 */ +	register struct kframe *kfp;	/* r10 */ +	register char **targv; +	register char **argv; +	extern int errno; +	extern void _mcleanup(); + +#ifdef lint +	kfp = 0; +	initcode = initcode = 0; +#else +	asm("lea 4(%ebp),%ebx");	/* catch it quick */ +#endif +	for (argv = targv = &kfp->kargv[0]; *targv++; /* void */) +		/* void */ ; +	if (targv >= (char **)(*argv)) +		--targv; +	environ = targv; +asm("eprol:"); + +#ifdef paranoid +	/* +	 * The standard I/O library assumes that file descriptors 0, 1, and 2 +	 * are open. If one of these descriptors is closed prior to the start  +	 * of the process, I/O gets very confused. To avoid this problem, we +	 * insure that the first three file descriptors are open before calling +	 * main(). Normally this is undefined, as it adds two unnecessary +	 * system calls. +	 */ +	do	{ +		fd = open("/dev/null", 2); +	} while (fd >= 0 && fd < 3); +	close(fd); +#endif + +#ifdef MCRT0 +	atexit(_mcleanup); +	monstartup(&eprol, &etext); +#endif +	errno = 0; +	if (argv[0]) +		if ((__progname = strrchr(argv[0], '/')) == NULL) +			__progname = argv[0]; +		else +			++__progname; +	exit(main(kfp->kargc, argv, environ)); +} + +#ifdef CRT0 +/* + * null moncontrol just in case some routine is compiled for profiling + */ +moncontrol(val) +	int val; +{ + +} +#endif diff --git a/lib/libc/compat-43/setregid.2 b/lib/libc/compat-43/setregid.2 new file mode 100644 index 000000000000..bf2624da1f27 --- /dev/null +++ b/lib/libc/compat-43/setregid.2 @@ -0,0 +1,93 @@ +.\" Copyright (c) 1980, 1991, 1993, 1994 +.\"	The 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. +.\" +.\"     @(#)setregid.2	8.2 (Berkeley) 4/16/94 +.\" +.Dd April 16, 1994 +.Dt SETREGID 2 +.Os BSD 4.2 +.Sh NAME +.Nm setregid +.Nd set real and effective group ID +.Sh SYNOPSIS +.Fd #include <unistd.h> +.Ft int +.Fn setregid "gid_t rgid" "gid_t egid" +.Sh DESCRIPTION +The real and effective group ID's of the current process +are set to the arguments. +Unprivileged users may change the real group +ID to the effective group ID and vice-versa; only the super-user may +make other changes. +.Pp +Supplying a value of -1 for either the real or effective +group ID forces the system to substitute the current +ID in place of the -1 parameter. +.Pp +The +.Fn setregid +function was intended to allow swapping +the real and effective group IDs +in set-group-ID programs to temporarily relinquish the set-group-ID value. +This function did not work correctly, +and its purpose is now better served by the use of the +.Fn setegid +function (see +.Xr setuid 2 ) . +.Pp +When setting the real and effective group IDs to the same value, +the standard +.Fn setgid +function is preferred. +.Sh RETURN VALUES +Upon successful completion, a value of 0 is returned.  Otherwise, +a value of -1 is returned and +.Va errno +is set to indicate the error. +.Sh ERRORS +.Bl -tag -width [EPERM] +.It Bq Er EPERM +The current process is not the super-user and a change +other than changing the effective group-id to the real group-id +was specified. +.El +.Sh SEE ALSO +.Xr getgid 2 , +.Xr setegid 2 , +.Xr setgid 2 , +.Xr setuid 2 +.Sh HISTORY +The +.Nm +function call appeared in +.Bx 4.2 +and was dropped in +.Bx 4.4 . diff --git a/lib/libc/compat-43/setregid.c b/lib/libc/compat-43/setregid.c new file mode 100644 index 000000000000..f91418ba650e --- /dev/null +++ b/lib/libc/compat-43/setregid.c @@ -0,0 +1,62 @@ +/* + * Copyright (c) 1993 + *	The 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. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static char sccsid[] = "@(#)setregid.c	8.1 (Berkeley) 6/2/93"; +#endif /* LIBC_SCCS and not lint */ + +#include <sys/types.h> +#include <errno.h> + +int +setregid(rgid, egid) +	gid_t rgid, egid; +{ +	static gid_t savedgid = -1; +	 +	if (savedgid == -1) +		savedgid = getegid(); +	/* +	 * we assume that the intent here is to be able to +	 * get back rgid priviledge. So we make sure that +	 * we will be able to do so, but do not actually +	 * set the rgid. +	 */ +	if (rgid != -1 && rgid != getgid() && rgid != savedgid) { +		errno = EPERM; +		return (-1); +	} +	if (egid != -1 && setegid(egid) < 0) +		return (-1); +	return (0); +} diff --git a/lib/libc/compat-43/setreuid.2 b/lib/libc/compat-43/setreuid.2 new file mode 100644 index 000000000000..980da123db31 --- /dev/null +++ b/lib/libc/compat-43/setreuid.2 @@ -0,0 +1,91 @@ +.\" Copyright (c) 1980, 1991, 1993, 1994 +.\"	The 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. +.\" +.\"     @(#)setreuid.2	8.2 (Berkeley) 4/16/94 +.\" +.Dd April 16, 1994 +.Dt SETREUID 2 +.Os BSD 4 +.Sh NAME +.Nm setreuid +.Nd set real and effective user ID's +.Sh SYNOPSIS +.Fd #include <unistd.h> +.Ft int +.Fn setreuid "uid_t ruid" "uid_t euid" +.Sh DESCRIPTION +The real and effective user IDs of the +current process are set according to the arguments. +If +.Fa ruid +or  +.Fa euid +is -1, the current uid is filled in by the system. +Unprivileged users may change the real user +ID to the effective user ID and vice-versa; only the super-user may +make other changes. +.Pp +The +.Fn setreuid +function has been used to swap the real and effective user IDs +in set-user-ID programs to temporarily relinquish the set-user-ID value. +This purpose is now better served by the use of the +.Fn seteuid +function (see +.Xr setuid 2 ) . +.Pp +When setting the real and effective user IDs to the same value, +the standard +.Fn setuid +function is preferred. +.Sh RETURN VALUES +Upon successful completion, a value of 0 is returned.  Otherwise, +a value of -1 is returned and +.Va errno +is set to indicate the error. +.Sh ERRORS +.Bl -tag -width [EPERM] +.It Bq Er EPERM +The current process is not the super-user and a change +other than changing the effective user-id to the real user-id +was specified. +.El +.Sh SEE ALSO +.Xr getuid 2 , +.Xr seteuid 2 , +.Xr setuid 2 +.Sh HISTORY +The +.Nm +function call appeared in +.Bx 4.2 +and was dropped in +.Bx 4.4 . diff --git a/lib/libc/compat-43/setreuid.c b/lib/libc/compat-43/setreuid.c new file mode 100644 index 000000000000..40316815814e --- /dev/null +++ b/lib/libc/compat-43/setreuid.c @@ -0,0 +1,62 @@ +/* + * Copyright (c) 1992, 1993 + *	The 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. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static char sccsid[] = "@(#)setreuid.c	8.1 (Berkeley) 6/2/93"; +#endif /* LIBC_SCCS and not lint */ + +#include <sys/types.h> +#include <errno.h> + +int +setreuid(ruid, euid) +	uid_t ruid, euid; +{ +	static uid_t saveduid = -1; +	 +	if (saveduid == -1) +		saveduid = geteuid(); +	/* +	 * we assume that the intent here is to be able to +	 * get back ruid priviledge. So we make sure that +	 * we will be able to do so, but do not actually +	 * set the ruid. +	 */ +	if (ruid != -1 && ruid != getuid() && ruid != saveduid) { +		errno = EPERM; +		return (-1); +	} +	if (euid != -1 && seteuid(euid) < 0) +		return (-1); +	return (0); +} diff --git a/lib/libc/gen/ctime.3 b/lib/libc/gen/ctime.3 new file mode 100644 index 000000000000..ff6a8efd5967 --- /dev/null +++ b/lib/libc/gen/ctime.3 @@ -0,0 +1,258 @@ +.\" Copyright (c) 1989, 1991, 1993 +.\"	The Regents of the University of California.  All rights reserved. +.\" +.\" This code is derived from software contributed to Berkeley by +.\" Arthur Olson. +.\" 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. +.\" +.\"     @(#)ctime.3	8.1 (Berkeley) 6/4/93 +.\" +.Dd June 4, 1993 +.Dt CTIME 3 +.Os BSD 4.3 +.Sh NAME +.Nm asctime , +.Nm ctime , +.Nm difftime , +.Nm gmtime , +.Nm localtime , +.Nm mktime +.Nd transform binary date and time value to +.Tn ASCII +.Sh SYNOPSIS +.Fd #include <sys/types.h> +.Fd #include <time.h> +.Vt extern char *tzname[2]; +.Ft char * +.Fn ctime "const time_t *clock" +.Ft double +.Fn difftime "time_t time1" "time_t time0" +.Ft char * +.Fn asctime "const struct tm *tm" +.Ft struct tm * +.Fn localtime "const time_t *clock" +.Ft struct tm * +.Fn gmtime "const time_t *clock" +.Ft time_t +.Fn mktime "struct tm *tm" +.Sh DESCRIPTION +The functions +.Fn ctime , +.Fn gmtime +and +.Fn localtime +all take as an argument a time value representing the time in seconds since +the Epoch (00:00:00 +.Tn UTC , +January 1, 1970; see +.Xr time 3 ) . +.Pp +The function +.Fn localtime +converts the time value pointed at by +.Fa clock , +and returns a pointer to a +.Dq Fa struct tm +(described below) which contains +the broken-out time information for the value after adjusting for the current +time zone (and any other factors such as Daylight Saving Time). +Time zone adjustments are performed as specified by the +.Ev TZ +environmental variable (see +.Xr tzset 3 ) . +The function +.Fn localtime +uses +.Xr tzset +to initialize time conversion information if +.Xr tzset +has not already been called by the process. +.Pp +After filling in the tm structure, +.Fn localtime +sets the +.Fa tm_isdst Ns 'th +element of +.Fa tzname +to a pointer to an +.Tn ASCII +string that's the time zone abbreviation to be +used with +.Fn localtime Ns 's +return value. +.Pp +The function +.Fn gmtime +similarly converts the time value, but without any time zone adjustment, +and returns a pointer to a tm structure (described below). +.Pp +The +.Fn ctime +function +adjusts the time value for the current time zone in the same manner as +.Fn localtime , +and returns a pointer to a 26-character string of the form: +.Bd -literal -offset indent +Thu Nov 24 18:22:48 1986\en\e0 +.Ed +.Pp +All the fields have constant width. +.Pp +The +.Fn asctime +function +converts the broken down time in the structure +.Fa tm +pointed at by +.Fa *tm +to the form +shown in the example above. +.Pp +The function +.Fn mktime +converts the broken-down time, expressed as local time, in the structure +pointed to by tm into a time value with the same encoding as that of the +values returned by the +.Xr time 3 +function, that is, seconds from the Epoch, +.Tn UTC . +.Pp +The original values of the +.Fa tm_wday +and +.Fa tm_yday +components of the structure are ignored, and the original values of the +other components are not restricted to their normal ranges. +(A positive or zero value for +.Fa tm_isdst +causes +.Fn mktime +to presume initially that summer time (for example, Daylight Saving Time) +is or is not in effect for the specified time, respectively. +A negative value for +.Fa tm_isdst +causes the +.Fn mktime +function to attempt to divine whether summer time is in effect for the +specified time.) +.Pp +On successful completion, the values of the +.Fa tm_wday +and +.Fa tm_yday +components of the structure are set appropriately, and the other components +are set to represent the specified calendar time, but with their values +forced to their normal ranges; the final value of +.Fa tm_mday +is not set until +.Fa tm_mon +and +.Fa tm_year +are determined. +.Fn Mktime +returns the specified calendar time; if the calendar time cannot be +represented, it returns \-1; +.Pp +The +.Fn difftime +function +returns the difference between two calendar times, +.Pf ( Fa time1 +- +.Fa time0 ) , +expressed in seconds. +.Pp +External declarations as well as the tm structure definition are in the  +.Aq Pa time.h +include file. +The tm structure includes at least the following fields: +.Bd -literal -offset indent +int tm_sec;	/\(** seconds (0 - 60) \(**/ +int tm_min;	/\(** minutes (0 - 59) \(**/ +int tm_hour;	/\(** hours (0 - 23) \(**/ +int tm_mday;	/\(** day of month (1 - 31) \(**/ +int tm_mon;	/\(** month of year (0 - 11) \(**/ +int tm_year;	/\(** year \- 1900 \(**/ +int tm_wday;	/\(** day of week (Sunday = 0) \(**/ +int tm_yday;	/\(** day of year (0 - 365) \(**/ +int tm_isdst;	/\(** is summer time in effect? \(**/ +char \(**tm_zone;	/\(** abbreviation of timezone name \(**/ +long tm_gmtoff;	/\(** offset from UTC in seconds \(**/ +.Ed +.Pp +The +field +.Fa tm_isdst +is non-zero if summer time is in effect. +.Pp +The field +.Fa tm_gmtoff +is the offset (in seconds) of the time represented from +.Tn UTC , +with positive +values indicating east of the Prime Meridian. +.Sh SEE ALSO +.Xr date 1 , +.Xr gettimeofday 2 , +.Xr getenv 3 , +.Xr time 3 , +.Xr tzset 3 , +.Xr tzfile 5 +.Sh HISTORY +This manual page is derived from +the time package contributed to Berkeley by +Arthur Olsen and which appeared in +.Bx 4.3 . +.Sh BUGS +Except for  +.Fn difftime +and +.Fn mktime , +these functions leaves their result in an internal static object and return +a pointer to that object. Subsequent calls to these +function will modify the same object. +.Pp +The +.Fa tm_zone +field of a returned tm structure points to a static array of characters, +which will also be overwritten by any subsequent calls (as well as by +subsequent calls to +.Xr tzset 3 +and +.Xr tzsetwall 3 ) . +.Pp +Use of the external variable +.Fa tzname +is discouraged; the +.Fa tm_zone +entry in the tm structure is preferred. +.Pp +Avoid using out-of-range values with +.Fn mktime +when setting up lunch with promptness sticklers in Riyadh. diff --git a/lib/libc/gen/ctime.c b/lib/libc/gen/ctime.c new file mode 100644 index 000000000000..b11e39b77c68 --- /dev/null +++ b/lib/libc/gen/ctime.c @@ -0,0 +1,1381 @@ +/* + * Copyright (c) 1987, 1989, 1993 + *	The Regents of the University of California.  All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Arthur David Olson of the National Cancer Institute. + * + * 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. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static char sccsid[] = "@(#)ctime.c	8.2 (Berkeley) 3/20/94"; +#endif /* LIBC_SCCS and not lint */ + +/* +** Leap second handling from Bradley White (bww@k.gp.cs.cmu.edu). +** POSIX-style TZ environment variable handling from Guy Harris +** (guy@auspex.com). +*/ + +/*LINTLIBRARY*/ + +#include <sys/param.h> +#include <fcntl.h> +#include <time.h> +#include <tzfile.h> +#include <string.h> +#include <ctype.h> +#include <stdio.h> +#include <unistd.h> + +#ifdef __STDC__ +#include <stdlib.h> + +#define P(s)		s +#define alloc_size_t	size_t +#define qsort_size_t	size_t +#define fread_size_t	size_t +#define fwrite_size_t	size_t + +#else /* !defined __STDC__ */ + +#define P(s)		() + +typedef char *		genericptr_t; +typedef unsigned	alloc_size_t; +typedef int		qsort_size_t; +typedef int		fread_size_t; +typedef int		fwrite_size_t; + +extern char *	calloc(); +extern char *	malloc(); +extern char *	realloc(); +extern char *	getenv(); + +#endif /* !defined __STDC__ */ + +extern time_t	time(); + +#define ACCESS_MODE	O_RDONLY +#define OPEN_MODE	O_RDONLY + +#ifndef WILDABBR +/* +** Someone might make incorrect use of a time zone abbreviation: +**	1.	They might reference tzname[0] before calling tzset (explicitly +**	 	or implicitly). +**	2.	They might reference tzname[1] before calling tzset (explicitly +**	 	or implicitly). +**	3.	They might reference tzname[1] after setting to a time zone +**		in which Daylight Saving Time is never observed. +**	4.	They might reference tzname[0] after setting to a time zone +**		in which Standard Time is never observed. +**	5.	They might reference tm.TM_ZONE after calling offtime. +** What's best to do in the above cases is open to debate; +** for now, we just set things up so that in any of the five cases +** WILDABBR is used.  Another possibility:  initialize tzname[0] to the +** string "tzname[0] used before set", and similarly for the other cases. +** And another:  initialize tzname[0] to "ERA", with an explanation in the +** manual page of what this "time zone abbreviation" means (doing this so +** that tzname[0] has the "normal" length of three characters). +*/ +#define WILDABBR	"   " +#endif /* !defined WILDABBR */ + +#ifndef TRUE +#define TRUE		1 +#define FALSE		0 +#endif /* !defined TRUE */ + +static const char GMT[] = "GMT"; + +struct ttinfo {				/* time type information */ +	long		tt_gmtoff;	/* GMT offset in seconds */ +	int		tt_isdst;	/* used to set tm_isdst */ +	int		tt_abbrind;	/* abbreviation list index */ +	int		tt_ttisstd;	/* TRUE if transition is std time */ +}; + +struct lsinfo {				/* leap second information */ +	time_t		ls_trans;	/* transition time */ +	long		ls_corr;	/* correction to apply */ +}; + +struct state { +	int		leapcnt; +	int		timecnt; +	int		typecnt; +	int		charcnt; +	time_t		ats[TZ_MAX_TIMES]; +	unsigned char	types[TZ_MAX_TIMES]; +	struct ttinfo	ttis[TZ_MAX_TYPES]; +	char		chars[(TZ_MAX_CHARS + 1 > sizeof GMT) ? +				TZ_MAX_CHARS + 1 : sizeof GMT]; +	struct lsinfo	lsis[TZ_MAX_LEAPS]; +}; + +struct rule { +	int		r_type;		/* type of rule--see below */ +	int		r_day;		/* day number of rule */ +	int		r_week;		/* week number of rule */ +	int		r_mon;		/* month number of rule */ +	long		r_time;		/* transition time of rule */ +}; + +#define	JULIAN_DAY		0	/* Jn - Julian day */ +#define	DAY_OF_YEAR		1	/* n - day of year */ +#define	MONTH_NTH_DAY_OF_WEEK	2	/* Mm.n.d - month, week, day of week */ + +/* +** Prototypes for static functions. +*/ + +static long		detzcode P((const char * codep)); +static const char *	getzname P((const char * strp)); +static const char *	getnum P((const char * strp, int * nump, int min, +				int max)); +static const char *	getsecs P((const char * strp, long * secsp)); +static const char *	getoffset P((const char * strp, long * offsetp)); +static const char *	getrule P((const char * strp, struct rule * rulep)); +static void		gmtload P((struct state * sp)); +static void		gmtsub P((const time_t * timep, long offset, +				struct tm * tmp)); +static void		localsub P((const time_t * timep, long offset, +				struct tm * tmp)); +static void		normalize P((int * tensptr, int * unitsptr, int base)); +static void		settzname P((void)); +static time_t		time1 P((struct tm * tmp, void (* funcp)(), +				long offset)); +static time_t		time2 P((struct tm *tmp, void (* funcp)(), +				long offset, int * okayp)); +static void		timesub P((const time_t * timep, long offset, +				const struct state * sp, struct tm * tmp)); +static int		tmcomp P((const struct tm * atmp, +				const struct tm * btmp)); +static time_t		transtime P((time_t janfirst, int year, +				const struct rule * rulep, long offset)); +static int		tzload P((const char * name, struct state * sp)); +static int		tzparse P((const char * name, struct state * sp, +				int lastditch)); + +#ifdef ALL_STATE +static struct state *	lclptr; +static struct state *	gmtptr; +#endif /* defined ALL_STATE */ + +#ifndef ALL_STATE +static struct state	lclmem; +static struct state	gmtmem; +#define lclptr		(&lclmem) +#define gmtptr		(&gmtmem) +#endif /* State Farm */ + +static int		lcl_is_set; +static int		gmt_is_set; + +char *			tzname[2] = { +	WILDABBR, +	WILDABBR +}; + +#ifdef USG_COMPAT +time_t			timezone = 0; +int			daylight = 0; +#endif /* defined USG_COMPAT */ + +#ifdef ALTZONE +time_t			altzone = 0; +#endif /* defined ALTZONE */ + +static long +detzcode(codep) +const char * const	codep; +{ +	register long	result; +	register int	i; + +	result = 0; +	for (i = 0; i < 4; ++i) +		result = (result << 8) | (codep[i] & 0xff); +	return result; +} + +static void +settzname() +{ +	register const struct state * const	sp = lclptr; +	register int				i; + +	tzname[0] = WILDABBR; +	tzname[1] = WILDABBR; +#ifdef USG_COMPAT +	daylight = 0; +	timezone = 0; +#endif /* defined USG_COMPAT */ +#ifdef ALTZONE +	altzone = 0; +#endif /* defined ALTZONE */ +#ifdef ALL_STATE +	if (sp == NULL) { +		tzname[0] = tzname[1] = GMT; +		return; +	} +#endif /* defined ALL_STATE */ +	for (i = 0; i < sp->typecnt; ++i) { +		register const struct ttinfo * const	ttisp = &sp->ttis[i]; + +		tzname[ttisp->tt_isdst] = +			(char *) &sp->chars[ttisp->tt_abbrind]; +#ifdef USG_COMPAT +		if (ttisp->tt_isdst) +			daylight = 1; +		if (i == 0 || !ttisp->tt_isdst) +			timezone = -(ttisp->tt_gmtoff); +#endif /* defined USG_COMPAT */ +#ifdef ALTZONE +		if (i == 0 || ttisp->tt_isdst) +			altzone = -(ttisp->tt_gmtoff); +#endif /* defined ALTZONE */ +	} +	/* +	** And to get the latest zone names into tzname. . . +	*/ +	for (i = 0; i < sp->timecnt; ++i) { +		register const struct ttinfo * const	ttisp = +							&sp->ttis[sp->types[i]]; + +		tzname[ttisp->tt_isdst] = +			(char *) &sp->chars[ttisp->tt_abbrind]; +	} +} + +static int +tzload(name, sp) +register const char *		name; +register struct state * const	sp; +{ +	register const char *	p; +	register int		i; +	register int		fid; + +	if (name == NULL && (name = TZDEFAULT) == NULL) +		return -1; +	{ +		char		fullname[FILENAME_MAX + 1]; + +		if (name[0] == ':') +			++name; +		if (name[0] != '/') { +			if ((p = TZDIR) == NULL) +				return -1; +			if ((strlen(p) + strlen(name) + 1) >= sizeof fullname) +				return -1; +			(void) strcpy(fullname, p); +			(void) strcat(fullname, "/"); +			(void) strcat(fullname, name); +			name = fullname; +		} +		if ((fid = open(name, OPEN_MODE)) == -1) +			return -1; +	} +	{ +		register const struct tzhead *	tzhp; +		char				buf[sizeof *sp + sizeof *tzhp]; +		int				ttisstdcnt; + +		i = read(fid, buf, sizeof buf); +		if (close(fid) != 0 || i < sizeof *tzhp) +			return -1; +		tzhp = (struct tzhead *) buf; +		ttisstdcnt = (int) detzcode(tzhp->tzh_ttisstdcnt); +		sp->leapcnt = (int) detzcode(tzhp->tzh_leapcnt); +		sp->timecnt = (int) detzcode(tzhp->tzh_timecnt); +		sp->typecnt = (int) detzcode(tzhp->tzh_typecnt); +		sp->charcnt = (int) detzcode(tzhp->tzh_charcnt); +		if (sp->leapcnt < 0 || sp->leapcnt > TZ_MAX_LEAPS || +			sp->typecnt <= 0 || sp->typecnt > TZ_MAX_TYPES || +			sp->timecnt < 0 || sp->timecnt > TZ_MAX_TIMES || +			sp->charcnt < 0 || sp->charcnt > TZ_MAX_CHARS || +			(ttisstdcnt != sp->typecnt && ttisstdcnt != 0)) +				return -1; +		if (i < sizeof *tzhp + +			sp->timecnt * (4 + sizeof (char)) + +			sp->typecnt * (4 + 2 * sizeof (char)) + +			sp->charcnt * sizeof (char) + +			sp->leapcnt * 2 * 4 + +			ttisstdcnt * sizeof (char)) +				return -1; +		p = buf + sizeof *tzhp; +		for (i = 0; i < sp->timecnt; ++i) { +			sp->ats[i] = detzcode(p); +			p += 4; +		} +		for (i = 0; i < sp->timecnt; ++i) { +			sp->types[i] = (unsigned char) *p++; +			if (sp->types[i] >= sp->typecnt) +				return -1; +		} +		for (i = 0; i < sp->typecnt; ++i) { +			register struct ttinfo *	ttisp; + +			ttisp = &sp->ttis[i]; +			ttisp->tt_gmtoff = detzcode(p); +			p += 4; +			ttisp->tt_isdst = (unsigned char) *p++; +			if (ttisp->tt_isdst != 0 && ttisp->tt_isdst != 1) +				return -1; +			ttisp->tt_abbrind = (unsigned char) *p++; +			if (ttisp->tt_abbrind < 0 || +				ttisp->tt_abbrind > sp->charcnt) +					return -1; +		} +		for (i = 0; i < sp->charcnt; ++i) +			sp->chars[i] = *p++; +		sp->chars[i] = '\0';	/* ensure '\0' at end */ +		for (i = 0; i < sp->leapcnt; ++i) { +			register struct lsinfo *	lsisp; + +			lsisp = &sp->lsis[i]; +			lsisp->ls_trans = detzcode(p); +			p += 4; +			lsisp->ls_corr = detzcode(p); +			p += 4; +		} +		for (i = 0; i < sp->typecnt; ++i) { +			register struct ttinfo *	ttisp; + +			ttisp = &sp->ttis[i]; +			if (ttisstdcnt == 0) +				ttisp->tt_ttisstd = FALSE; +			else { +				ttisp->tt_ttisstd = *p++; +				if (ttisp->tt_ttisstd != TRUE && +					ttisp->tt_ttisstd != FALSE) +						return -1; +			} +		} +	} +	return 0; +} + +static const int	mon_lengths[2][MONSPERYEAR] = { +	31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31, +	31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 +}; + +static const int	year_lengths[2] = { +	DAYSPERNYEAR, DAYSPERLYEAR +}; + +/* +** Given a pointer into a time zone string, scan until a character that is not +** a valid character in a zone name is found.  Return a pointer to that +** character. +*/ + +static const char * +getzname(strp) +register const char *	strp; +{ +	register char	c; + +	while ((c = *strp) != '\0' && !isdigit(c) && c != ',' && c != '-' && +		c != '+') +			++strp; +	return strp; +} + +/* +** Given a pointer into a time zone string, extract a number from that string. +** Check that the number is within a specified range; if it is not, return +** NULL. +** Otherwise, return a pointer to the first character not part of the number. +*/ + +static const char * +getnum(strp, nump, min, max) +register const char *	strp; +int * const		nump; +const int		min; +const int		max; +{ +	register char	c; +	register int	num; + +	if (strp == NULL || !isdigit(*strp)) +		return NULL; +	num = 0; +	while ((c = *strp) != '\0' && isdigit(c)) { +		num = num * 10 + (c - '0'); +		if (num > max) +			return NULL;	/* illegal value */ +		++strp; +	} +	if (num < min) +		return NULL;		/* illegal value */ +	*nump = num; +	return strp; +} + +/* +** Given a pointer into a time zone string, extract a number of seconds, +** in hh[:mm[:ss]] form, from the string. +** If any error occurs, return NULL. +** Otherwise, return a pointer to the first character not part of the number +** of seconds. +*/ + +static const char * +getsecs(strp, secsp) +register const char *	strp; +long * const		secsp; +{ +	int	num; + +	strp = getnum(strp, &num, 0, HOURSPERDAY); +	if (strp == NULL) +		return NULL; +	*secsp = num * SECSPERHOUR; +	if (*strp == ':') { +		++strp; +		strp = getnum(strp, &num, 0, MINSPERHOUR - 1); +		if (strp == NULL) +			return NULL; +		*secsp += num * SECSPERMIN; +		if (*strp == ':') { +			++strp; +			strp = getnum(strp, &num, 0, SECSPERMIN - 1); +			if (strp == NULL) +				return NULL; +			*secsp += num; +		} +	} +	return strp; +} + +/* +** Given a pointer into a time zone string, extract an offset, in +** [+-]hh[:mm[:ss]] form, from the string. +** If any error occurs, return NULL. +** Otherwise, return a pointer to the first character not part of the time. +*/ + +static const char * +getoffset(strp, offsetp) +register const char *	strp; +long * const		offsetp; +{ +	register int	neg; + +	if (*strp == '-') { +		neg = 1; +		++strp; +	} else if (isdigit(*strp) || *strp++ == '+') +		neg = 0; +	else	return NULL;		/* illegal offset */ +	strp = getsecs(strp, offsetp); +	if (strp == NULL) +		return NULL;		/* illegal time */ +	if (neg) +		*offsetp = -*offsetp; +	return strp; +} + +/* +** Given a pointer into a time zone string, extract a rule in the form +** date[/time].  See POSIX section 8 for the format of "date" and "time". +** If a valid rule is not found, return NULL. +** Otherwise, return a pointer to the first character not part of the rule. +*/ + +static const char * +getrule(strp, rulep) +const char *			strp; +register struct rule * const	rulep; +{ +	if (*strp == 'J') { +		/* +		** Julian day. +		*/ +		rulep->r_type = JULIAN_DAY; +		++strp; +		strp = getnum(strp, &rulep->r_day, 1, DAYSPERNYEAR); +	} else if (*strp == 'M') { +		/* +		** Month, week, day. +		*/ +		rulep->r_type = MONTH_NTH_DAY_OF_WEEK; +		++strp; +		strp = getnum(strp, &rulep->r_mon, 1, MONSPERYEAR); +		if (strp == NULL) +			return NULL; +		if (*strp++ != '.') +			return NULL; +		strp = getnum(strp, &rulep->r_week, 1, 5); +		if (strp == NULL) +			return NULL; +		if (*strp++ != '.') +			return NULL; +		strp = getnum(strp, &rulep->r_day, 0, DAYSPERWEEK - 1); +	} else if (isdigit(*strp)) { +		/* +		** Day of year. +		*/ +		rulep->r_type = DAY_OF_YEAR; +		strp = getnum(strp, &rulep->r_day, 0, DAYSPERLYEAR - 1); +	} else	return NULL;		/* invalid format */ +	if (strp == NULL) +		return NULL; +	if (*strp == '/') { +		/* +		** Time specified. +		*/ +		++strp; +		strp = getsecs(strp, &rulep->r_time); +	} else	rulep->r_time = 2 * SECSPERHOUR;	/* default = 2:00:00 */ +	return strp; +} + +/* +** Given the Epoch-relative time of January 1, 00:00:00 GMT, in a year, the +** year, a rule, and the offset from GMT at the time that rule takes effect, +** calculate the Epoch-relative time that rule takes effect. +*/ + +static time_t +transtime(janfirst, year, rulep, offset) +const time_t				janfirst; +const int				year; +register const struct rule * const	rulep; +const long				offset; +{ +	register int	leapyear; +	register time_t	value; +	register int	i; +	int		d, m1, yy0, yy1, yy2, dow; + +	leapyear = isleap(year); +	switch (rulep->r_type) { + +	case JULIAN_DAY: +		/* +		** Jn - Julian day, 1 == January 1, 60 == March 1 even in leap +		** years. +		** In non-leap years, or if the day number is 59 or less, just +		** add SECSPERDAY times the day number-1 to the time of +		** January 1, midnight, to get the day. +		*/ +		value = janfirst + (rulep->r_day - 1) * SECSPERDAY; +		if (leapyear && rulep->r_day >= 60) +			value += SECSPERDAY; +		break; + +	case DAY_OF_YEAR: +		/* +		** n - day of year. +		** Just add SECSPERDAY times the day number to the time of +		** January 1, midnight, to get the day. +		*/ +		value = janfirst + rulep->r_day * SECSPERDAY; +		break; + +	case MONTH_NTH_DAY_OF_WEEK: +		/* +		** Mm.n.d - nth "dth day" of month m. +		*/ +		value = janfirst; +		for (i = 0; i < rulep->r_mon - 1; ++i) +			value += mon_lengths[leapyear][i] * SECSPERDAY; + +		/* +		** Use Zeller's Congruence to get day-of-week of first day of +		** month. +		*/ +		m1 = (rulep->r_mon + 9) % 12 + 1; +		yy0 = (rulep->r_mon <= 2) ? (year - 1) : year; +		yy1 = yy0 / 100; +		yy2 = yy0 % 100; +		dow = ((26 * m1 - 2) / 10 + +			1 + yy2 + yy2 / 4 + yy1 / 4 - 2 * yy1) % 7; +		if (dow < 0) +			dow += DAYSPERWEEK; + +		/* +		** "dow" is the day-of-week of the first day of the month.  Get +		** the day-of-month (zero-origin) of the first "dow" day of the +		** month. +		*/ +		d = rulep->r_day - dow; +		if (d < 0) +			d += DAYSPERWEEK; +		for (i = 1; i < rulep->r_week; ++i) { +			if (d + DAYSPERWEEK >= +				mon_lengths[leapyear][rulep->r_mon - 1]) +					break; +			d += DAYSPERWEEK; +		} + +		/* +		** "d" is the day-of-month (zero-origin) of the day we want. +		*/ +		value += d * SECSPERDAY; +		break; +	} + +	/* +	** "value" is the Epoch-relative time of 00:00:00 GMT on the day in +	** question.  To get the Epoch-relative time of the specified local +	** time on that day, add the transition time and the current offset +	** from GMT. +	*/ +	return value + rulep->r_time + offset; +} + +/* +** Given a POSIX section 8-style TZ string, fill in the rule tables as +** appropriate. +*/ + +static int +tzparse(name, sp, lastditch) +const char *			name; +register struct state * const	sp; +const int			lastditch; +{ +	const char *			stdname; +	const char *			dstname; +	int				stdlen; +	int				dstlen; +	long				stdoffset; +	long				dstoffset; +	register time_t *		atp; +	register unsigned char *	typep; +	register char *			cp; +	register int			load_result; + +	stdname = name; +	if (lastditch) { +		stdlen = strlen(name);	/* length of standard zone name */ +		name += stdlen; +		if (stdlen >= sizeof sp->chars) +			stdlen = (sizeof sp->chars) - 1; +	} else { +		name = getzname(name); +		stdlen = name - stdname; +		if (stdlen < 3) +			return -1; +	} +	if (*name == '\0') +		return -1; +	else { +		name = getoffset(name, &stdoffset); +		if (name == NULL) +			return -1; +	} +	load_result = tzload(TZDEFRULES, sp); +	if (load_result != 0) +		sp->leapcnt = 0;		/* so, we're off a little */ +	if (*name != '\0') { +		dstname = name; +		name = getzname(name); +		dstlen = name - dstname;	/* length of DST zone name */ +		if (dstlen < 3) +			return -1; +		if (*name != '\0' && *name != ',' && *name != ';') { +			name = getoffset(name, &dstoffset); +			if (name == NULL) +				return -1; +		} else	dstoffset = stdoffset - SECSPERHOUR; +		if (*name == ',' || *name == ';') { +			struct rule	start; +			struct rule	end; +			register int	year; +			register time_t	janfirst; +			time_t		starttime; +			time_t		endtime; + +			++name; +			if ((name = getrule(name, &start)) == NULL) +				return -1; +			if (*name++ != ',') +				return -1; +			if ((name = getrule(name, &end)) == NULL) +				return -1; +			if (*name != '\0') +				return -1; +			sp->typecnt = 2;	/* standard time and DST */ +			/* +			** Two transitions per year, from EPOCH_YEAR to 2037. +			*/ +			sp->timecnt = 2 * (2037 - EPOCH_YEAR + 1); +			if (sp->timecnt > TZ_MAX_TIMES) +				return -1; +			sp->ttis[0].tt_gmtoff = -dstoffset; +			sp->ttis[0].tt_isdst = 1; +			sp->ttis[0].tt_abbrind = stdlen + 1; +			sp->ttis[1].tt_gmtoff = -stdoffset; +			sp->ttis[1].tt_isdst = 0; +			sp->ttis[1].tt_abbrind = 0; +			atp = sp->ats; +			typep = sp->types; +			janfirst = 0; +			for (year = EPOCH_YEAR; year <= 2037; ++year) { +				starttime = transtime(janfirst, year, &start, +					stdoffset); +				endtime = transtime(janfirst, year, &end, +					dstoffset); +				if (starttime > endtime) { +					*atp++ = endtime; +					*typep++ = 1;	/* DST ends */ +					*atp++ = starttime; +					*typep++ = 0;	/* DST begins */ +				} else { +					*atp++ = starttime; +					*typep++ = 0;	/* DST begins */ +					*atp++ = endtime; +					*typep++ = 1;	/* DST ends */ +				} +				janfirst += +					year_lengths[isleap(year)] * SECSPERDAY; +			} +		} else { +			int		sawstd; +			int		sawdst; +			long		stdfix; +			long		dstfix; +			long		oldfix; +			int		isdst; +			register int	i; + +			if (*name != '\0') +				return -1; +			if (load_result != 0) +				return -1; +			/* +			** Compute the difference between the real and +			** prototype standard and summer time offsets +			** from GMT, and put the real standard and summer +			** time offsets into the rules in place of the +			** prototype offsets. +			*/ +			sawstd = FALSE; +			sawdst = FALSE; +			stdfix = 0; +			dstfix = 0; +			for (i = 0; i < sp->typecnt; ++i) { +				if (sp->ttis[i].tt_isdst) { +					oldfix = dstfix; +					dstfix = +					    sp->ttis[i].tt_gmtoff + dstoffset; +					if (sawdst && (oldfix != dstfix)) +						return -1; +					sp->ttis[i].tt_gmtoff = -dstoffset; +					sp->ttis[i].tt_abbrind = stdlen + 1; +					sawdst = TRUE; +				} else { +					oldfix = stdfix; +					stdfix = +					    sp->ttis[i].tt_gmtoff + stdoffset; +					if (sawstd && (oldfix != stdfix)) +						return -1; +					sp->ttis[i].tt_gmtoff = -stdoffset; +					sp->ttis[i].tt_abbrind = 0; +					sawstd = TRUE; +				} +			} +			/* +			** Make sure we have both standard and summer time. +			*/ +			if (!sawdst || !sawstd) +				return -1; +			/* +			** Now correct the transition times by shifting +			** them by the difference between the real and +			** prototype offsets.  Note that this difference +			** can be different in standard and summer time; +			** the prototype probably has a 1-hour difference +			** between standard and summer time, but a different +			** difference can be specified in TZ. +			*/ +			isdst = FALSE;	/* we start in standard time */ +			for (i = 0; i < sp->timecnt; ++i) { +				register const struct ttinfo *	ttisp; + +				/* +				** If summer time is in effect, and the +				** transition time was not specified as +				** standard time, add the summer time +				** offset to the transition time; +				** otherwise, add the standard time offset +				** to the transition time. +				*/ +				ttisp = &sp->ttis[sp->types[i]]; +				sp->ats[i] += +					(isdst && !ttisp->tt_ttisstd) ? +						dstfix : stdfix; +				isdst = ttisp->tt_isdst; +			} +		} +	} else { +		dstlen = 0; +		sp->typecnt = 1;		/* only standard time */ +		sp->timecnt = 0; +		sp->ttis[0].tt_gmtoff = -stdoffset; +		sp->ttis[0].tt_isdst = 0; +		sp->ttis[0].tt_abbrind = 0; +	} +	sp->charcnt = stdlen + 1; +	if (dstlen != 0) +		sp->charcnt += dstlen + 1; +	if (sp->charcnt > sizeof sp->chars) +		return -1; +	cp = sp->chars; +	(void) strncpy(cp, stdname, stdlen); +	cp += stdlen; +	*cp++ = '\0'; +	if (dstlen != 0) { +		(void) strncpy(cp, dstname, dstlen); +		*(cp + dstlen) = '\0'; +	} +	return 0; +} + +static void +gmtload(sp) +struct state * const	sp; +{ +	if (tzload(GMT, sp) != 0) +		(void) tzparse(GMT, sp, TRUE); +} + +void +tzset() +{ +	register const char *	name; +	void tzsetwall(); + +	name = getenv("TZ"); +	if (name == NULL) { +		tzsetwall(); +		return; +	} +	lcl_is_set = TRUE; +#ifdef ALL_STATE +	if (lclptr == NULL) { +		lclptr = (struct state *) malloc(sizeof *lclptr); +		if (lclptr == NULL) { +			settzname();	/* all we can do */ +			return; +		} +	} +#endif /* defined ALL_STATE */ +	if (*name == '\0') { +		/* +		** User wants it fast rather than right. +		*/ +		lclptr->leapcnt = 0;		/* so, we're off a little */ +		lclptr->timecnt = 0; +		lclptr->ttis[0].tt_gmtoff = 0; +		lclptr->ttis[0].tt_abbrind = 0; +		(void) strcpy(lclptr->chars, GMT); +	} else if (tzload(name, lclptr) != 0) +		if (name[0] == ':' || tzparse(name, lclptr, FALSE) != 0) +			(void) gmtload(lclptr); +	settzname(); +} + +void +tzsetwall() +{ +	lcl_is_set = TRUE; +#ifdef ALL_STATE +	if (lclptr == NULL) { +		lclptr = (struct state *) malloc(sizeof *lclptr); +		if (lclptr == NULL) { +			settzname();	/* all we can do */ +			return; +		} +	} +#endif /* defined ALL_STATE */ +	if (tzload((char *) NULL, lclptr) != 0) +		gmtload(lclptr); +	settzname(); +} + +/* +** The easy way to behave "as if no library function calls" localtime +** is to not call it--so we drop its guts into "localsub", which can be +** freely called.  (And no, the PANS doesn't require the above behavior-- +** but it *is* desirable.) +** +** The unused offset argument is for the benefit of mktime variants. +*/ + +/*ARGSUSED*/ +static void +localsub(timep, offset, tmp) +const time_t * const	timep; +const long		offset; +struct tm * const	tmp; +{ +	register struct state *	sp; +	register const struct ttinfo *	ttisp; +	register int			i; +	const time_t			t = *timep; + +	if (!lcl_is_set) +		tzset(); +	sp = lclptr; +#ifdef ALL_STATE +	if (sp == NULL) { +		gmtsub(timep, offset, tmp); +		return; +	} +#endif /* defined ALL_STATE */ +	if (sp->timecnt == 0 || t < sp->ats[0]) { +		i = 0; +		while (sp->ttis[i].tt_isdst) +			if (++i >= sp->typecnt) { +				i = 0; +				break; +			} +	} else { +		for (i = 1; i < sp->timecnt; ++i) +			if (t < sp->ats[i]) +				break; +		i = sp->types[i - 1]; +	} +	ttisp = &sp->ttis[i]; +	/* +	** To get (wrong) behavior that's compatible with System V Release 2.0 +	** you'd replace the statement below with +	**	t += ttisp->tt_gmtoff; +	**	timesub(&t, 0L, sp, tmp); +	*/ +	timesub(&t, ttisp->tt_gmtoff, sp, tmp); +	tmp->tm_isdst = ttisp->tt_isdst; +	tzname[tmp->tm_isdst] = (char *) &sp->chars[ttisp->tt_abbrind]; +	tmp->tm_zone = &sp->chars[ttisp->tt_abbrind]; +} + +struct tm * +localtime(timep) +const time_t * const	timep; +{ +	static struct tm	tm; + +	localsub(timep, 0L, &tm); +	return &tm; +} + +/* +** gmtsub is to gmtime as localsub is to localtime. +*/ + +static void +gmtsub(timep, offset, tmp) +const time_t * const	timep; +const long		offset; +struct tm * const	tmp; +{ +	if (!gmt_is_set) { +		gmt_is_set = TRUE; +#ifdef ALL_STATE +		gmtptr = (struct state *) malloc(sizeof *gmtptr); +		if (gmtptr != NULL) +#endif /* defined ALL_STATE */ +			gmtload(gmtptr); +	} +	timesub(timep, offset, gmtptr, tmp); +	/* +	** Could get fancy here and deliver something such as +	** "GMT+xxxx" or "GMT-xxxx" if offset is non-zero, +	** but this is no time for a treasure hunt. +	*/ +	if (offset != 0) +		tmp->tm_zone = WILDABBR; +	else { +#ifdef ALL_STATE +		if (gmtptr == NULL) +			tmp->TM_ZONE = GMT; +		else	tmp->TM_ZONE = gmtptr->chars; +#endif /* defined ALL_STATE */ +#ifndef ALL_STATE +		tmp->tm_zone = gmtptr->chars; +#endif /* State Farm */ +	} +} + +struct tm * +gmtime(timep) +const time_t * const	timep; +{ +	static struct tm	tm; + +	gmtsub(timep, 0L, &tm); +	return &tm; +} + +static void +timesub(timep, offset, sp, tmp) +const time_t * const			timep; +const long				offset; +register const struct state * const	sp; +register struct tm * const		tmp; +{ +	register const struct lsinfo *	lp; +	register long			days; +	register long			rem; +	register int			y; +	register int			yleap; +	register const int *		ip; +	register long			corr; +	register int			hit; +	register int			i; + +	corr = 0; +	hit = FALSE; +#ifdef ALL_STATE +	i = (sp == NULL) ? 0 : sp->leapcnt; +#endif /* defined ALL_STATE */ +#ifndef ALL_STATE +	i = sp->leapcnt; +#endif /* State Farm */ +	while (--i >= 0) { +		lp = &sp->lsis[i]; +		if (*timep >= lp->ls_trans) { +			if (*timep == lp->ls_trans) +				hit = ((i == 0 && lp->ls_corr > 0) || +					lp->ls_corr > sp->lsis[i - 1].ls_corr); +			corr = lp->ls_corr; +			break; +		} +	} +	days = *timep / SECSPERDAY; +	rem = *timep % SECSPERDAY; +#ifdef mc68k +	if (*timep == 0x80000000) { +		/* +		** A 3B1 muffs the division on the most negative number. +		*/ +		days = -24855; +		rem = -11648; +	} +#endif /* mc68k */ +	rem += (offset - corr); +	while (rem < 0) { +		rem += SECSPERDAY; +		--days; +	} +	while (rem >= SECSPERDAY) { +		rem -= SECSPERDAY; +		++days; +	} +	tmp->tm_hour = (int) (rem / SECSPERHOUR); +	rem = rem % SECSPERHOUR; +	tmp->tm_min = (int) (rem / SECSPERMIN); +	tmp->tm_sec = (int) (rem % SECSPERMIN); +	if (hit) +		/* +		** A positive leap second requires a special +		** representation.  This uses "... ??:59:60". +		*/ +		++(tmp->tm_sec); +	tmp->tm_wday = (int) ((EPOCH_WDAY + days) % DAYSPERWEEK); +	if (tmp->tm_wday < 0) +		tmp->tm_wday += DAYSPERWEEK; +	y = EPOCH_YEAR; +	if (days >= 0) +		for ( ; ; ) { +			yleap = isleap(y); +			if (days < (long) year_lengths[yleap]) +				break; +			++y; +			days = days - (long) year_lengths[yleap]; +		} +	else do { +		--y; +		yleap = isleap(y); +		days = days + (long) year_lengths[yleap]; +	} while (days < 0); +	tmp->tm_year = y - TM_YEAR_BASE; +	tmp->tm_yday = (int) days; +	ip = mon_lengths[yleap]; +	for (tmp->tm_mon = 0; days >= (long) ip[tmp->tm_mon]; ++(tmp->tm_mon)) +		days = days - (long) ip[tmp->tm_mon]; +	tmp->tm_mday = (int) (days + 1); +	tmp->tm_isdst = 0; +	tmp->tm_gmtoff = offset; +} + +/* +** A la X3J11 +*/ + +char * +asctime(timeptr) +register const struct tm *	timeptr; +{ +	static const char	wday_name[DAYSPERWEEK][3] = { +		"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" +	}; +	static const char	mon_name[MONSPERYEAR][3] = { +		"Jan", "Feb", "Mar", "Apr", "May", "Jun", +		"Jul", "Aug", "Sep", "Oct", "Nov", "Dec" +	}; +	static char	result[26]; + +	(void) sprintf(result, "%.3s %.3s%3d %02.2d:%02.2d:%02.2d %d\n", +		wday_name[timeptr->tm_wday], +		mon_name[timeptr->tm_mon], +		timeptr->tm_mday, timeptr->tm_hour, +		timeptr->tm_min, timeptr->tm_sec, +		TM_YEAR_BASE + timeptr->tm_year); +	return result; +} + +char * +ctime(timep) +const time_t * const	timep; +{ +	return asctime(localtime(timep)); +} + +/* +** Adapted from code provided by Robert Elz, who writes: +**	The "best" way to do mktime I think is based on an idea of Bob +**	Kridle's (so its said...) from a long time ago. (mtxinu!kridle now). +**	It does a binary search of the time_t space.  Since time_t's are +**	just 32 bits, its a max of 32 iterations (even at 64 bits it +**	would still be very reasonable). +*/ + +#ifndef WRONG +#define WRONG	(-1) +#endif /* !defined WRONG */ + +static void +normalize(tensptr, unitsptr, base) +int * const	tensptr; +int * const	unitsptr; +const int	base; +{ +	if (*unitsptr >= base) { +		*tensptr += *unitsptr / base; +		*unitsptr %= base; +	} else if (*unitsptr < 0) { +		*tensptr -= 1 + (-(*unitsptr + 1)) / base; +		*unitsptr = base - 1 - (-(*unitsptr + 1)) % base; +	} +} + +static int +tmcomp(atmp, btmp) +register const struct tm * const atmp; +register const struct tm * const btmp; +{ +	register int	result; + +	if ((result = (atmp->tm_year - btmp->tm_year)) == 0 && +		(result = (atmp->tm_mon - btmp->tm_mon)) == 0 && +		(result = (atmp->tm_mday - btmp->tm_mday)) == 0 && +		(result = (atmp->tm_hour - btmp->tm_hour)) == 0 && +		(result = (atmp->tm_min - btmp->tm_min)) == 0) +			result = atmp->tm_sec - btmp->tm_sec; +	return result; +} + +static time_t +time2(tmp, funcp, offset, okayp) +struct tm * const	tmp; +void (* const		funcp)(); +const long		offset; +int * const		okayp; +{ +	register const struct state *	sp; +	register int			dir; +	register int			bits; +	register int			i, j ; +	register int			saved_seconds; +	time_t				newt; +	time_t				t; +	struct tm			yourtm, mytm; + +	*okayp = FALSE; +	yourtm = *tmp; +	if (yourtm.tm_sec >= SECSPERMIN + 2 || yourtm.tm_sec < 0) +		normalize(&yourtm.tm_min, &yourtm.tm_sec, SECSPERMIN); +	normalize(&yourtm.tm_hour, &yourtm.tm_min, MINSPERHOUR); +	normalize(&yourtm.tm_mday, &yourtm.tm_hour, HOURSPERDAY); +	normalize(&yourtm.tm_year, &yourtm.tm_mon, MONSPERYEAR); +	while (yourtm.tm_mday <= 0) { +		--yourtm.tm_year; +		yourtm.tm_mday += +			year_lengths[isleap(yourtm.tm_year + TM_YEAR_BASE)]; +	} +	while (yourtm.tm_mday > DAYSPERLYEAR) { +		yourtm.tm_mday -= +		    year_lengths[isleap(yourtm.tm_year + TM_YEAR_BASE)]; +		++yourtm.tm_year; +	} +	for ( ; ; ) { +		i = mon_lengths[isleap(yourtm.tm_year + +			TM_YEAR_BASE)][yourtm.tm_mon]; +		if (yourtm.tm_mday <= i) +			break; +		yourtm.tm_mday -= i; +		if (++yourtm.tm_mon >= MONSPERYEAR) { +			yourtm.tm_mon = 0; +			++yourtm.tm_year; +		} +	} +	saved_seconds = yourtm.tm_sec; +	yourtm.tm_sec = 0; +	/* +	** Calculate the number of magnitude bits in a time_t +	** (this works regardless of whether time_t is +	** signed or unsigned, though lint complains if unsigned). +	*/ +	for (bits = 0, t = 1; t > 0; ++bits, t <<= 1) +		; +	/* +	** If time_t is signed, then 0 is the median value, +	** if time_t is unsigned, then 1 << bits is median. +	*/ +	t = (t < 0) ? 0 : ((time_t) 1 << bits); +	for ( ; ; ) { +		(*funcp)(&t, offset, &mytm); +		dir = tmcomp(&mytm, &yourtm); +		if (dir != 0) { +			if (bits-- < 0) +				return WRONG; +			if (bits < 0) +				--t; +			else if (dir > 0) +				t -= (time_t) 1 << bits; +			else	t += (time_t) 1 << bits; +			continue; +		} +		if (yourtm.tm_isdst < 0 || mytm.tm_isdst == yourtm.tm_isdst) +			break; +		/* +		** Right time, wrong type. +		** Hunt for right time, right type. +		** It's okay to guess wrong since the guess +		** gets checked. +		*/ +		sp = (const struct state *) +			((funcp == localsub) ? lclptr : gmtptr); +#ifdef ALL_STATE +		if (sp == NULL) +			return WRONG; +#endif /* defined ALL_STATE */ +		for (i = 0; i < sp->typecnt; ++i) { +			if (sp->ttis[i].tt_isdst != yourtm.tm_isdst) +				continue; +			for (j = 0; j < sp->typecnt; ++j) { +				if (sp->ttis[j].tt_isdst == yourtm.tm_isdst) +					continue; +				newt = t + sp->ttis[j].tt_gmtoff - +					sp->ttis[i].tt_gmtoff; +				(*funcp)(&newt, offset, &mytm); +				if (tmcomp(&mytm, &yourtm) != 0) +					continue; +				if (mytm.tm_isdst != yourtm.tm_isdst) +					continue; +				/* +				** We have a match. +				*/ +				t = newt; +				goto label; +			} +		} +		return WRONG; +	} +label: +	t += saved_seconds; +	(*funcp)(&t, offset, tmp); +	*okayp = TRUE; +	return t; +} + +static time_t +time1(tmp, funcp, offset) +struct tm * const	tmp; +void (* const		funcp)(); +const long		offset; +{ +	register time_t			t; +	register const struct state *	sp; +	register int			samei, otheri; +	int				okay; + +	if (tmp->tm_isdst > 1) +		tmp->tm_isdst = 1; +	t = time2(tmp, funcp, offset, &okay); +	if (okay || tmp->tm_isdst < 0) +		return t; +	/* +	** We're supposed to assume that somebody took a time of one type +	** and did some math on it that yielded a "struct tm" that's bad. +	** We try to divine the type they started from and adjust to the +	** type they need. +	*/ +	sp = (const struct state *) ((funcp == localsub) ? lclptr : gmtptr); +#ifdef ALL_STATE +	if (sp == NULL) +		return WRONG; +#endif /* defined ALL_STATE */ +	for (samei = 0; samei < sp->typecnt; ++samei) { +		if (sp->ttis[samei].tt_isdst != tmp->tm_isdst) +			continue; +		for (otheri = 0; otheri < sp->typecnt; ++otheri) { +			if (sp->ttis[otheri].tt_isdst == tmp->tm_isdst) +				continue; +			tmp->tm_sec += sp->ttis[otheri].tt_gmtoff - +					sp->ttis[samei].tt_gmtoff; +			tmp->tm_isdst = !tmp->tm_isdst; +			t = time2(tmp, funcp, offset, &okay); +			if (okay) +				return t; +			tmp->tm_sec -= sp->ttis[otheri].tt_gmtoff - +					sp->ttis[samei].tt_gmtoff; +			tmp->tm_isdst = !tmp->tm_isdst; +		} +	} +	return WRONG; +} + +time_t +mktime(tmp) +struct tm * const	tmp; +{ +	return time1(tmp, localsub, 0L); +} diff --git a/lib/libc/gen/difftime.c b/lib/libc/gen/difftime.c new file mode 100644 index 000000000000..394133087203 --- /dev/null +++ b/lib/libc/gen/difftime.c @@ -0,0 +1,45 @@ +/* + * Copyright (c) 1989, 1993 + *	The 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. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static char sccsid[] = "@(#)difftime.c	8.1 (Berkeley) 6/4/93"; +#endif /* LIBC_SCCS and not lint */ + +#include <sys/types.h> + +double +difftime(time1, time0) +	time_t time1, time0; +{ +	return(time1 - time0); +} diff --git a/lib/libc/i386/gen/_setjmp.s b/lib/libc/i386/gen/_setjmp.s new file mode 100644 index 000000000000..47e319a4abda --- /dev/null +++ b/lib/libc/i386/gen/_setjmp.s @@ -0,0 +1,78 @@ +/*- + * Copyright (c) 1990, 1993 + *	The Regents of the University of California.  All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * William Jolitz. + * + * 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. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +	.asciz "@(#)_setjmp.s	8.1 (Berkeley) 6/4/93" +#endif /* LIBC_SCCS and not lint */ + +/* + * C library -- _setjmp, _longjmp + * + *	_longjmp(a,v) + * will generate a "return(v)" from the last call to + *	_setjmp(a) + * by restoring registers from the stack. + * The previous signal state is NOT restored. + */ + +#include "DEFS.h" + +ENTRY(_setjmp) +	movl	4(%esp),%eax +	movl	0(%esp),%edx +	movl	%edx, 0(%eax)		/* rta */ +	movl	%ebx, 4(%eax) +	movl	%esp, 8(%eax) +	movl	%ebp,12(%eax) +	movl	%esi,16(%eax) +	movl	%edi,20(%eax) +	movl	$0,%eax +	ret + +ENTRY(_longjmp) +	movl	4(%esp),%edx +	movl	8(%esp),%eax +	movl	0(%edx),%ecx +	movl	4(%edx),%ebx +	movl	8(%edx),%esp +	movl	12(%edx),%ebp +	movl	16(%edx),%esi +	movl	20(%edx),%edi +	cmpl	$0,%eax +	jne	1f +	movl	$1,%eax +1:	movl	%ecx,0(%esp) +	ret diff --git a/lib/libc/i386/gen/alloca.s b/lib/libc/i386/gen/alloca.s new file mode 100644 index 000000000000..a2d6a41f3af9 --- /dev/null +++ b/lib/libc/i386/gen/alloca.s @@ -0,0 +1,57 @@ +/*- + * Copyright (c) 1990, 1993 + *	The Regents of the University of California.  All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * William Jolitz. + * + * 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. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +	.asciz "@(#)alloca.s	8.1 (Berkeley) 6/4/93" +#endif /* LIBC_SCCS and not lint */ + +/* like alloc, but automatic automatic free in return */ + +#include "DEFS.h" + +ENTRY(alloca) +	popl	%edx		/*  pop return addr */ +	popl	%eax		/*  pop amount to allocate */ +	movl	%esp,%ecx +	addl	$3,%eax		/*  round up to next word */ +	andl	$0xfffffffc,%eax +	subl	%eax,%esp +	movl	%esp,%eax	/* base of newly allocated space */ +	pushl	8(%ecx)		/* copy possible saved registers */ +	pushl	4(%ecx) +	pushl	0(%ecx) +	pushl	%eax		/* dummy to pop at callsite */ +	jmp	%edx		/* "return" */ diff --git a/lib/libc/i386/gen/divsi3.s b/lib/libc/i386/gen/divsi3.s new file mode 100644 index 000000000000..946a4a16c472 --- /dev/null +++ b/lib/libc/i386/gen/divsi3.s @@ -0,0 +1,46 @@ +/*- + * Copyright (c) 1990, 1993 + *	The Regents of the University of California.  All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * William Jolitz. + * + * 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. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +	.asciz "@(#)divsi3.s	8.1 (Berkeley) 6/4/93" +#endif /* LIBC_SCCS and not lint */ + +	.globl ___divsi3 +___divsi3: +	movl 4(%esp),%eax +	cltd +	idivl 8(%esp) +	ret diff --git a/lib/libc/i386/gen/fabs.s b/lib/libc/i386/gen/fabs.s new file mode 100644 index 000000000000..40e72c80ef74 --- /dev/null +++ b/lib/libc/i386/gen/fabs.s @@ -0,0 +1,46 @@ +/*- + * Copyright (c) 1990, 1993 + *	The Regents of the University of California.  All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * William Jolitz. + * + * 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. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +	.asciz "@(#)fabs.s	8.1 (Berkeley) 6/4/93" +#endif /* LIBC_SCCS and not lint */ + +#include "DEFS.h" + +ENTRY(fabs) +	fldl	4(%esp) +	fabs +	ret diff --git a/lib/libc/i386/gen/fixdfsi.s b/lib/libc/i386/gen/fixdfsi.s new file mode 100644 index 000000000000..138d0788018e --- /dev/null +++ b/lib/libc/i386/gen/fixdfsi.s @@ -0,0 +1,46 @@ +/*- + * Copyright (c) 1991, 1993 + *	The Regents of the University of California.  All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * William Jolitz. + * + * 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. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +	.asciz "@(#)fixdfsi.s	8.1 (Berkeley) 6/4/93" +#endif /* LIBC_SCCS and not lint */ + +	.globl ___fixdfsi +___fixdfsi: +	fldl	4(%esp) +	fistpl	4(%esp) +	movl	4(%esp),%eax +	ret diff --git a/lib/libc/i386/gen/fixunsdfsi.s b/lib/libc/i386/gen/fixunsdfsi.s new file mode 100644 index 000000000000..7025bb6bd9cf --- /dev/null +++ b/lib/libc/i386/gen/fixunsdfsi.s @@ -0,0 +1,60 @@ +/*- + * Copyright (c) 1990, 1993 + *	The Regents of the University of California.  All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * William Jolitz. + * + * 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. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +	.asciz "@(#)fixunsdfsi.s	8.1	6/4/93" +#endif /* LIBC_SCCS and not lint */ + +	.globl ___fixunsdfsi +___fixunsdfsi: +	fldl	4(%esp)		/* argument double to accum stack */ +	frndint			/* create integer */ +	fcoml	fbiggestsigned	/* bigger than biggest signed? */ +	fstsw	%ax +	sahf +	jnb	1f +	 +	fistpl	4(%esp) +	movl	4(%esp),%eax +	ret + +1:	fsubl	fbiggestsigned	/* reduce for proper conversion */ +	fistpl	4(%esp)		/* convert */ +	movl	4(%esp),%eax +	orl	$0x80000000,%eax	/* restore bias */ +	ret + +fbiggestsigned:	.double	0r2147483648.0 diff --git a/lib/libc/i386/gen/modf.s b/lib/libc/i386/gen/modf.s new file mode 100644 index 000000000000..2551237df3e6 --- /dev/null +++ b/lib/libc/i386/gen/modf.s @@ -0,0 +1,75 @@ +/*- + * Copyright (c) 1990, 1993 + *	The Regents of the University of California.  All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Sean Eric Fagan. + * + * 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. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +	.asciz "@(#)modf.s	8.1 (Berkeley) 6/4/93" +#endif /* LIBC_SCCS and not lint */ + +/* + * modf(value, iptr): return fractional part of value, and stores the + * integral part into iptr (a pointer to double). + * + * Written by Sean Eric Fagan (sef@kithrup.COM) + * Sun Mar 11 20:27:30 PST 1990 + */ + +/* With CHOP mode on, frndint behaves as TRUNC does.  Useful. */ +.text +.globl _modf +_modf: +	pushl %ebp +	movl %esp,%ebp +	subl $16,%esp +	fnstcw -12(%ebp) +	movw -12(%ebp),%dx +	orw $3072,%dx +	movw %dx,-16(%ebp) +	fldcw -16(%ebp) +	fldl 8(%ebp) +	frndint +	fstpl -8(%ebp) +	fldcw -12(%ebp) +	movl 16(%ebp),%eax +	movl -8(%ebp),%edx +	movl -4(%ebp),%ecx +	movl %edx,(%eax) +	movl %ecx,4(%eax) +	fldl 8(%ebp) +	fsubl -8(%ebp) +	jmp L1 +L1: +	leave +	ret diff --git a/lib/libc/i386/gen/setjmp.s b/lib/libc/i386/gen/setjmp.s new file mode 100644 index 000000000000..b24da115efe2 --- /dev/null +++ b/lib/libc/i386/gen/setjmp.s @@ -0,0 +1,86 @@ +/*- + * Copyright (c) 1990, 1993 + *	The Regents of the University of California.  All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * William Jolitz. + * + * 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. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +	.asciz "@(#)setjmp.s	8.1 (Berkeley) 6/4/93" +#endif /* LIBC_SCCS and not lint */ + +/* + * C library -- _setjmp, _longjmp + * + *	longjmp(a,v) + * will generate a "return(v)" from the last call to + *	setjmp(a) + * by restoring registers from the stack. + * The previous signal state is restored. + */ + +#include "DEFS.h" + +ENTRY(setjmp) +	pushl	$0 +	call	_sigblock +	popl	%edx +	movl	4(%esp),%ecx  +	movl	0(%esp),%edx +	movl	%edx, 0(%ecx) +	movl	%ebx, 4(%ecx) +	movl	%esp, 8(%ecx) +	movl	%ebp,12(%ecx) +	movl	%esi,16(%ecx) +	movl	%edi,20(%ecx) +	movl	%eax,24(%ecx) +	movl	$0,%eax +	ret + +ENTRY(longjmp) +	movl	4(%esp),%edx +	pushl	24(%edx) +	call	_sigsetmask +	popl	%eax +	movl	4(%esp),%edx +	movl	8(%esp),%eax +	movl	0(%edx),%ecx +	movl	4(%edx),%ebx +	movl	8(%edx),%esp +	movl	12(%edx),%ebp +	movl	16(%edx),%esi +	movl	20(%edx),%edi +	cmpl	$0,%eax +	jne	1f +	movl	$1,%eax +1:	movl	%ecx,0(%esp) +	ret diff --git a/lib/libc/i386/gen/udivsi3.s b/lib/libc/i386/gen/udivsi3.s new file mode 100644 index 000000000000..791e5264e336 --- /dev/null +++ b/lib/libc/i386/gen/udivsi3.s @@ -0,0 +1,46 @@ +/*- + * Copyright (c) 1990, 1993 + *	The Regents of the University of California.  All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * William Jolitz. + * + * 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. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +	.asciz "@(#)udivsi3.s	8.1 (Berkeley) 6/4/93" +#endif /* LIBC_SCCS and not lint */ + +	.globl ___udivsi3 +___udivsi3: +	movl 4(%esp),%eax +	xorl %edx,%edx +	divl 8(%esp) +	ret diff --git a/lib/libc/i386/net/htonl.s b/lib/libc/i386/net/htonl.s new file mode 100644 index 000000000000..01d93c840fbe --- /dev/null +++ b/lib/libc/i386/net/htonl.s @@ -0,0 +1,50 @@ +/*- + * Copyright (c) 1990, 1993 + *	The Regents of the University of California.  All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * William Jolitz. + * + * 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. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +	.asciz "@(#)htonl.s	8.1 (Berkeley) 6/4/93" +#endif /* LIBC_SCCS and not lint */ + +/* netorder = htonl(hostorder) */ + +#include "DEFS.h" + +ENTRY(htonl) +	movl	4(%esp),%eax +	xchgb	%al,%ah +	roll	$16,%eax +	xchgb	%al,%ah +	ret diff --git a/lib/libc/i386/net/htons.s b/lib/libc/i386/net/htons.s new file mode 100644 index 000000000000..74a76abd3b5e --- /dev/null +++ b/lib/libc/i386/net/htons.s @@ -0,0 +1,48 @@ +/*- + * Copyright (c) 1990, 1993 + *	The Regents of the University of California.  All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * William Jolitz. + * + * 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. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +	.asciz "@(#)htons.s	8.1 (Berkeley) 6/4/93" +#endif /* LIBC_SCCS and not lint */ + +/* netorder = htons(hostorder) */ + +#include "DEFS.h" + +ENTRY(htons) +	movzwl	4(%esp),%eax +	xchgb	%al,%ah +	ret diff --git a/lib/libc/i386/net/ntohl.s b/lib/libc/i386/net/ntohl.s new file mode 100644 index 000000000000..29802facea31 --- /dev/null +++ b/lib/libc/i386/net/ntohl.s @@ -0,0 +1,50 @@ +/*- + * Copyright (c) 1990, 1993 + *	The Regents of the University of California.  All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * William Jolitz. + * + * 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. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +	.asciz "@(#)ntohl.s	8.1 (Berkeley) 6/4/93" +#endif /* LIBC_SCCS and not lint */ + +/* hostorder = ntohl(netorder) */ + +#include "DEFS.h" + +ENTRY(ntohl) +	movl	4(%esp),%eax +	xchgb	%al,%ah +	roll	$16,%eax +	xchgb	%al,%ah +	ret diff --git a/lib/libc/i386/net/ntohs.s b/lib/libc/i386/net/ntohs.s new file mode 100644 index 000000000000..4b521dad3023 --- /dev/null +++ b/lib/libc/i386/net/ntohs.s @@ -0,0 +1,48 @@ +/*- + * Copyright (c) 1990, 1993 + *	The Regents of the University of California.  All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * William Jolitz. + * + * 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. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +	.asciz "@(#)ntohs.s	8.1 (Berkeley) 6/4/93" +#endif /* LIBC_SCCS and not lint */ + +/* hostorder = ntohs(netorder) */ + +#include "DEFS.h" + +ENTRY(ntohs) +	movzwl	4(%esp),%eax +	xchgb	%al,%ah +	ret diff --git a/lib/libc/i386/stdlib/abs.s b/lib/libc/i386/stdlib/abs.s new file mode 100644 index 000000000000..755ea5693ae0 --- /dev/null +++ b/lib/libc/i386/stdlib/abs.s @@ -0,0 +1,48 @@ +/*- + * Copyright (c) 1990, 1993 + *	The Regents of the University of California.  All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * William Jolitz. + * + * 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. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +	.asciz "@(#)abs.s	8.1 (Berkeley) 6/4/93" +#endif /* LIBC_SCCS and not lint */ + +#include "DEFS.h" + +ENTRY(abs) +	movl	4(%esp),%eax +	cmpl	$0,%eax +	jge	1f +	negl	%eax +1:	ret diff --git a/lib/libc/i386/string/bzero.s b/lib/libc/i386/string/bzero.s new file mode 100644 index 000000000000..79a5a694f93c --- /dev/null +++ b/lib/libc/i386/string/bzero.s @@ -0,0 +1,53 @@ +/*- + * Copyright (c) 1990, 1993 + *	The Regents of the University of California.  All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * William Jolitz. + * + * 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. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +	.asciz "@(#)bzero.s	8.1 (Berkeley) 6/4/93" +#endif /* LIBC_SCCS and not lint */ + +/* bzero (base,cnt) */ + +	.globl _bzero +_bzero: +	pushl	%edi +	movl	8(%esp),%edi +	movl	12(%esp),%ecx +	movb	$0x00,%al +	cld +	rep +	stosb +	popl	%edi +	ret diff --git a/lib/libc/i386/sys/Ovfork.s b/lib/libc/i386/sys/Ovfork.s new file mode 100644 index 000000000000..c7e6b8a9e7b0 --- /dev/null +++ b/lib/libc/i386/sys/Ovfork.s @@ -0,0 +1,70 @@ +/*- + * Copyright (c) 1990, 1993 + *	The Regents of the University of California.  All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * William Jolitz. + * + * 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. + */ + +#if defined(SYSLIBC_SCCS) && !defined(lint) +	.asciz "@(#)Ovfork.s	8.1 (Berkeley) 6/4/93" +#endif /* SYSLIBC_SCCS and not lint */ + +#include "SYS.h" + +/* + * pid = vfork(); + * + * %edx == 0 in parent process, %edx == 1 in child process. + * %eax == pid of child in parent, %eax == pid of parent in child. + * + */ +	.set	vfork,66 +.globl	_vfork + +_vfork: +	popl	%ecx		/* my rta into ecx */ +	movl	$vfork, %eax +	LCALL(7,0) +	jb	verror +vforkok: +	cmpl	$0,%edx		/* child process? */ +	jne	child		/* yes */ +	jmp 	parent  +.globl	_errno +verror: +	movl	%eax,_errno +	movl	$-1,%eax +	jmp	%ecx +child: +	movl	$0,%eax +parent: +	jmp	%ecx diff --git a/lib/libc/i386/sys/brk.s b/lib/libc/i386/sys/brk.s new file mode 100644 index 000000000000..f85186cf265d --- /dev/null +++ b/lib/libc/i386/sys/brk.s @@ -0,0 +1,65 @@ +/*- + * Copyright (c) 1990, 1993 + *	The Regents of the University of California.  All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * William Jolitz. + * + * 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. + */ + +#if defined(SYSLIBC_SCCS) && !defined(lint) +	.asciz "@(#)brk.s	8.1 (Berkeley) 6/4/93" +#endif /* SYSLIBC_SCCS and not lint */ + +#include "SYS.h" + +#define	SYS_brk		17 + +	.globl	curbrk +	.globl	minbrk +ENTRY(_brk) +	jmp	ok + +ENTRY(brk) +	movl	4(%esp),%eax +	cmpl	%eax,minbrk +	jl	ok +	movl	minbrk,%eax +	movl	%eax,4(%esp) +ok: +	lea	SYS_brk,%eax +	LCALL(7,0) +	jb	err +	movl	4(%esp),%eax +	movl	%eax,curbrk +	movl	$0,%eax +	ret +err: +	jmp	cerror diff --git a/lib/libc/i386/sys/cerror.s b/lib/libc/i386/sys/cerror.s new file mode 100644 index 000000000000..cc2d82fc7717 --- /dev/null +++ b/lib/libc/i386/sys/cerror.s @@ -0,0 +1,47 @@ +/*- + * Copyright (c) 1990, 1993 + *	The Regents of the University of California.  All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * William Jolitz. + * + * 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. + */ + +#if defined(SYSLIBC_SCCS) && !defined(lint) +	.asciz "@(#)cerror.s	8.1 (Berkeley) 6/4/93" +#endif /* SYSLIBC_SCCS and not lint */ + +#include "SYS.h" + +	.globl	_errno +cerror: +	movl	%eax,_errno +	movl	$-1,%eax +	ret diff --git a/lib/libc/i386/sys/exect.s b/lib/libc/i386/sys/exect.s new file mode 100644 index 000000000000..6b42cf84e500 --- /dev/null +++ b/lib/libc/i386/sys/exect.s @@ -0,0 +1,52 @@ +/*- + * Copyright (c) 1990, 1993 + *	The Regents of the University of California.  All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * William Jolitz. + * + * 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. + */ + +#if defined(SYSLIBC_SCCS) && !defined(lint) +	.asciz "@(#)exect.s	8.1 (Berkeley) 6/4/93" +#endif /* SYSLIBC_SCCS and not lint */ + +#include "SYS.h" +#include <machine/psl.h> + +ENTRY(exect) +	lea	SYS_execve,%eax +	pushf +	popl	%edx +	orl	$ PSL_T,%edx +	pushl	%edx +	popf +	LCALL(7,0) +	jmp	cerror		/* exect(file, argv, env); */ diff --git a/lib/libc/i386/sys/fork.s b/lib/libc/i386/sys/fork.s new file mode 100644 index 000000000000..ff4d94879417 --- /dev/null +++ b/lib/libc/i386/sys/fork.s @@ -0,0 +1,48 @@ +/*- + * Copyright (c) 1990, 1993 + *	The Regents of the University of California.  All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * William Jolitz. + * + * 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. + */ + +#if defined(SYSLIBC_SCCS) && !defined(lint) +	.asciz "@(#)fork.s	8.1 (Berkeley) 6/4/93" +#endif /* SYSLIBC_SCCS and not lint */ + +#include "SYS.h" + +SYSCALL(fork) +	cmpl	$0,%edx	/* parent, since %edx == 0 in parent, 1 in child */ +	je	1f +	movl	$0,%eax +1: +	ret		/* pid = fork(); */ diff --git a/lib/libc/i386/sys/mount.s b/lib/libc/i386/sys/mount.s new file mode 100644 index 000000000000..ac418f756f58 --- /dev/null +++ b/lib/libc/i386/sys/mount.s @@ -0,0 +1,45 @@ +/*- + * Copyright (c) 1990, 1993 + *	The Regents of the University of California.  All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * William Jolitz. + * + * 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. + */ + +#if defined(SYSLIBC_SCCS) && !defined(lint) +	.asciz "@(#)mount.s	8.1 (Berkeley) 6/4/93" +#endif /* SYSLIBC_SCCS and not lint */ + +#include "SYS.h" + +SYSCALL(mount) +	movl	$0,%eax +	ret diff --git a/lib/libc/i386/sys/pipe.s b/lib/libc/i386/sys/pipe.s new file mode 100644 index 000000000000..6469397053d6 --- /dev/null +++ b/lib/libc/i386/sys/pipe.s @@ -0,0 +1,48 @@ +/*- + * Copyright (c) 1990, 1993 + *	The Regents of the University of California.  All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * William Jolitz. + * + * 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. + */ + +#if defined(SYSLIBC_SCCS) && !defined(lint) +	.asciz "@(#)pipe.s	8.1 (Berkeley) 6/4/93" +#endif /* SYSLIBC_SCCS and not lint */ + +#include "SYS.h" + +SYSCALL(pipe) +	movl	4(%esp),%ecx +	movl	%eax,(%ecx) +	movl	%edx,4(%ecx) +	movl	$0,%eax +	ret diff --git a/lib/libc/i386/sys/ptrace.s b/lib/libc/i386/sys/ptrace.s new file mode 100644 index 000000000000..98994eabdef9 --- /dev/null +++ b/lib/libc/i386/sys/ptrace.s @@ -0,0 +1,51 @@ +/*- + * Copyright (c) 1990, 1993 + *	The Regents of the University of California.  All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * William Jolitz. + * + * 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. + */ + +#if defined(SYSLIBC_SCCS) && !defined(lint) +	.asciz "@(#)ptrace.s	8.1 (Berkeley) 6/4/93" +#endif /* SYSLIBC_SCCS and not lint */ + +#include "SYS.h" + +ENTRY(ptrace) +	xorl	%eax,%eax +	movl	%eax,_errno +	lea	SYS_ptrace,%eax +	LCALL(7,0) +	jb	err +	ret +err: +	jmp	cerror diff --git a/lib/libc/i386/sys/reboot.s b/lib/libc/i386/sys/reboot.s new file mode 100644 index 000000000000..020bea067b52 --- /dev/null +++ b/lib/libc/i386/sys/reboot.s @@ -0,0 +1,44 @@ +/*- + * Copyright (c) 1990, 1993 + *	The Regents of the University of California.  All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * William Jolitz. + * + * 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. + */ + +#if defined(SYSLIBC_SCCS) && !defined(lint) +	.asciz "@(#)reboot.s	8.1 (Berkeley) 6/4/93" +#endif /* SYSLIBC_SCCS and not lint */ + +#include "SYS.h" + +SYSCALL(reboot) +	iret diff --git a/lib/libc/i386/sys/sbrk.s b/lib/libc/i386/sys/sbrk.s new file mode 100644 index 000000000000..7fecd93535a8 --- /dev/null +++ b/lib/libc/i386/sys/sbrk.s @@ -0,0 +1,65 @@ +/*- + * Copyright (c) 1990, 1993 + *	The Regents of the University of California.  All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * William Jolitz. + * + * 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. + */ + +#if defined(SYSLIBC_SCCS) && !defined(lint) +	.asciz "@(#)sbrk.s	8.1 (Berkeley) 6/4/93" +#endif /* SYSLIBC_SCCS and not lint */ + +#include "SYS.h" + +#define	SYS_brk		17 + +	.globl	_end +	.globl	minbrk +	.globl	curbrk + +	.data +minbrk:	.long	_end +curbrk:	.long	_end +	.text + +ENTRY(sbrk) +	movl	4(%esp),%ecx +	movl	curbrk,%eax +	addl	%eax,4(%esp) +	lea	SYS_brk,%eax +	LCALL(7,0) +	jb	err +	movl	curbrk,%eax +	addl	%ecx,curbrk +	ret +err: +	jmp	cerror diff --git a/lib/libc/i386/sys/setlogin.s b/lib/libc/i386/sys/setlogin.s new file mode 100644 index 000000000000..43d31d7b919c --- /dev/null +++ b/lib/libc/i386/sys/setlogin.s @@ -0,0 +1,47 @@ +/*- + * Copyright (c) 1991, 1993 + *	The Regents of the University of California.  All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * William Jolitz. + * + * 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. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +	.asciz "@(#)setlogin.s	8.1 (Berkeley) 6/4/93" +#endif /* LIBC_SCCS and not lint */ + +#include "SYS.h" + +.globl	__logname_valid		/* in getlogin() */ + +SYSCALL(setlogin) +	movl	$0,__logname_valid +	ret				/* setlogin(name) */ diff --git a/lib/libc/i386/sys/sigpending.s b/lib/libc/i386/sys/sigpending.s new file mode 100644 index 000000000000..63b06a2d935a --- /dev/null +++ b/lib/libc/i386/sys/sigpending.s @@ -0,0 +1,47 @@ +/*- + * Copyright (c) 1990, 1993 + *	The Regents of the University of California.  All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * William Jolitz. + * + * 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. + */ + +#if defined(SYSLIBC_SCCS) && !defined(lint) +	.asciz "@(#)sigpending.s	8.1 (Berkeley) 6/4/93" +#endif /* SYSLIBC_SCCS and not lint */ + +#include "SYS.h" + +SYSCALL(sigpending) +	movl	4(%esp),%ecx		# fetch pointer to... +	movl	%eax,(%ecx)		# store old mask +	xorl	%eax,%eax +	ret diff --git a/lib/libc/i386/sys/sigprocmask.s b/lib/libc/i386/sys/sigprocmask.s new file mode 100644 index 000000000000..ef91e80611ad --- /dev/null +++ b/lib/libc/i386/sys/sigprocmask.s @@ -0,0 +1,64 @@ +/*- + * Copyright (c) 1990, 1993 + *	The Regents of the University of California.  All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * William Jolitz. + * + * 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. + */ + +#if defined(SYSLIBC_SCCS) && !defined(lint) +	.asciz "@(#)sigprocmask.s	8.1 (Berkeley) 6/4/93" +#endif /* SYSLIBC_SCCS and not lint */ + +#include "SYS.h" + +err: +	jmp	cerror + +ENTRY(sigprocmask) +	movl	8(%esp),%ecx		# fetch new sigset pointer +	cmpl	$0,%ecx			# check new sigset pointer +	jne	1f			# if not null, indirect +/*	movl	$0,8(%esp)		# null mask pointer: block empty set */ +	movl	$1,4(%esp)		# SIG_BLOCK +	jmp	2f +1:	movl	(%ecx),%ecx		# fetch indirect  ... +	movl	%ecx,8(%esp)		# to new mask arg +2:	movl	$ SYS_sigprocmask , %eax +	LCALL(0x7,0) +	jb	err +	movl	12(%esp),%ecx		# fetch old mask requested +	cmpl	$0,%ecx			# test if old mask requested +	je	out +	movl	%eax,(%ecx)		# store old mask +out: +	xorl	%eax,%eax +	ret diff --git a/lib/libc/i386/sys/sigreturn.s b/lib/libc/i386/sys/sigreturn.s new file mode 100644 index 000000000000..1bd6a3b876c6 --- /dev/null +++ b/lib/libc/i386/sys/sigreturn.s @@ -0,0 +1,54 @@ +/*- + * Copyright (c) 1990, 1993 + *	The Regents of the University of California.  All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * William Jolitz. + * + * 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. + */ + +#if defined(SYSLIBC_SCCS) && !defined(lint) +	.asciz "@(#)sigreturn.s	8.1 (Berkeley) 6/4/93" +#endif /* SYSLIBC_SCCS and not lint */ + +#include "SYS.h" + +/* + * We must preserve the state of the registers as the user has set them up. + */ +#ifdef PROF +#undef ENTRY +#define	ENTRY(x) \ +	.globl _/**/x; .align 2; _/**/x:  pusha ; \ +	.data; 1:; .long 0; .text; movl $1b,%eax; call mcount; popa ; nop +#endif /* PROF */ + +SYSCALL(sigreturn) +	ret diff --git a/lib/libc/i386/sys/sigsuspend.s b/lib/libc/i386/sys/sigsuspend.s new file mode 100644 index 000000000000..afbc1ba96a9d --- /dev/null +++ b/lib/libc/i386/sys/sigsuspend.s @@ -0,0 +1,54 @@ +/*- + * Copyright (c) 1990, 1993 + *	The Regents of the University of California.  All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * William Jolitz. + * + * 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. + */ + +#if defined(SYSLIBC_SCCS) && !defined(lint) +	.asciz "@(#)sigsuspend.s	8.1 (Berkeley) 6/4/93" +#endif /* SYSLIBC_SCCS and not lint */ + +#include "SYS.h" + +err: +	jmp	cerror + +ENTRY(sigsuspend) +	movl	4(%esp),%eax		# fetch mask arg +	movl	(%eax),%eax		# indirect to mask arg +	movl	%eax,4(%esp) +	movl	$ SYS_sigsuspend ,%eax +	LCALL(0x7,0) +	jb	err +	xorl	%eax,%eax		# shouldn t happen +	ret diff --git a/lib/libc/i386/sys/syscall.s b/lib/libc/i386/sys/syscall.s new file mode 100644 index 000000000000..189f4dd7b641 --- /dev/null +++ b/lib/libc/i386/sys/syscall.s @@ -0,0 +1,51 @@ +/*- + * Copyright (c) 1990, 1993 + *	The Regents of the University of California.  All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * William Jolitz. + * + * 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. + */ + +#if defined(SYSLIBC_SCCS) && !defined(lint) +	.asciz "@(#)syscall.s	8.1 (Berkeley) 6/4/93" +#endif /* SYSLIBC_SCCS and not lint */ + +#include "SYS.h" + +ENTRY(syscall) +	pop	%ecx	/* rta */ +	pop	%eax	/* syscall number */ +	push	%ecx +	LCALL(7,0) +	jb	1f +	ret +1: +	jmp	cerror diff --git a/lib/libc/net/getnetbyname.c b/lib/libc/net/getnetbyname.c new file mode 100644 index 000000000000..5082a7abbfb5 --- /dev/null +++ b/lib/libc/net/getnetbyname.c @@ -0,0 +1,62 @@ +/* + * Copyright (c) 1983, 1993 + *	The 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. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static char sccsid[] = "@(#)getnetbyname.c	8.1 (Berkeley) 6/4/93"; +#endif /* LIBC_SCCS and not lint */ + +#include <netdb.h> +#include <string.h> + +extern int _net_stayopen; + +struct netent * +getnetbyname(name) +	register const char *name; +{ +	register struct netent *p; +	register char **cp; + +	setnetent(_net_stayopen); +	while (p = getnetent()) { +		if (strcmp(p->n_name, name) == 0) +			break; +		for (cp = p->n_aliases; *cp != 0; cp++) +			if (strcmp(*cp, name) == 0) +				goto found; +	} +found: +	if (!_net_stayopen) +		endnetent(); +	return (p); +} diff --git a/lib/libc/net/getnetent.c b/lib/libc/net/getnetent.c new file mode 100644 index 000000000000..49ec9b745abc --- /dev/null +++ b/lib/libc/net/getnetent.c @@ -0,0 +1,121 @@ +/* + * Copyright (c) 1983, 1993 + *	The 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. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static char sccsid[] = "@(#)getnetent.c	8.1 (Berkeley) 6/4/93"; +#endif /* LIBC_SCCS and not lint */ + +#include <sys/types.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include <netdb.h> +#include <stdio.h> +#include <string.h> + +#define	MAXALIASES	35 + +static FILE *netf; +static char line[BUFSIZ+1]; +static struct netent net; +static char *net_aliases[MAXALIASES]; +int _net_stayopen; + +void +setnetent(f) +	int f; +{ +	if (netf == NULL) +		netf = fopen(_PATH_NETWORKS, "r" ); +	else +		rewind(netf); +	_net_stayopen |= f; +} + +void +endnetent() +{ +	if (netf) { +		fclose(netf); +		netf = NULL; +	} +	_net_stayopen = 0; +} + +struct netent * +getnetent() +{ +	char *p; +	register char *cp, **q; + +	if (netf == NULL && (netf = fopen(_PATH_NETWORKS, "r" )) == NULL) +		return (NULL); +again: +	p = fgets(line, BUFSIZ, netf); +	if (p == NULL) +		return (NULL); +	if (*p == '#') +		goto again; +	cp = strpbrk(p, "#\n"); +	if (cp == NULL) +		goto again; +	*cp = '\0'; +	net.n_name = p; +	cp = strpbrk(p, " \t"); +	if (cp == NULL) +		goto again; +	*cp++ = '\0'; +	while (*cp == ' ' || *cp == '\t') +		cp++; +	p = strpbrk(cp, " \t"); +	if (p != NULL) +		*p++ = '\0'; +	net.n_net = inet_network(cp); +	net.n_addrtype = AF_INET; +	q = net.n_aliases = net_aliases; +	if (p != NULL)  +		cp = p; +	while (cp && *cp) { +		if (*cp == ' ' || *cp == '\t') { +			cp++; +			continue; +		} +		if (q < &net_aliases[MAXALIASES - 1]) +			*q++ = cp; +		cp = strpbrk(cp, " \t"); +		if (cp != NULL) +			*cp++ = '\0'; +	} +	*q = NULL; +	return (&net); +} diff --git a/lib/libc/net/getservent.3 b/lib/libc/net/getservent.3 new file mode 100644 index 000000000000..f90571ebb97b --- /dev/null +++ b/lib/libc/net/getservent.3 @@ -0,0 +1,155 @@ +.\" Copyright (c) 1983, 1991, 1993 +.\"	The 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. +.\" +.\"     @(#)getservent.3	8.4 (Berkeley) 5/25/95 +.\" +.Dd May 25, 1995 +.Dt GETSERVENT 3 +.Os BSD 4.2 +.Sh NAME +.Nm getservent , +.Nm getservbyport , +.Nm getservbyname , +.Nm setservent , +.Nm endservent +.Nd get service entry +.Sh SYNOPSIS +.Fd #include <netdb.h> +.Ft struct servent * +.Fn getservent  +.Ft struct servent * +.Fn getservbyname "char *name" "char *proto" +.Ft struct servent * +.Fn getservbyport "int port" proto +.Ft void +.Fn setservent "int stayopen" +.Ft void +.Fn endservent void +.Sh DESCRIPTION +The +.Fn getservent , +.Fn getservbyname , +and +.Fn getservbyport +functions +each return a pointer to an object with the +following structure +containing the broken-out +fields of a line in the network services data base, +.Pa /etc/services . +.Bd -literal -offset indent +struct	servent { +	char	*s_name;	/* official name of service */ +	char	**s_aliases;	/* alias list */ +	int	s_port;		/* port service resides at */ +	char	*s_proto;	/* protocol to use */ +}; +.Ed +.Pp +The members of this structure are: +.Bl -tag -width s_aliases +.It Fa s_name +The official name of the service. +.It Fa s_aliases +A NULL-terminated list of alternate names for the service. +.It Fa s_port +The port number at which the service resides. +Port numbers are returned in network byte order. +.It Fa s_proto +The name of the protocol to use when contacting the +service. +.El +.Pp +The +.Fn getservent +function +reads the next line of the file, opening the file if necessary. +.Pp +The +.Fn setservent +function +opens and rewinds the file.  If the +.Fa stayopen +flag is non-zero, +the net data base will not be closed after each call to  +.Fn getservbyname +or +.Fn getservbyport . +.Pp +The +.Fn endservent +function +closes the file. +.Pp +The +.Fn getservbyname +and +.Fn getservbyport +functions +sequentially search from the beginning +of the file until a matching +protocol name or +port number is found, +or until +.Dv EOF +is encountered. +If a protocol name is also supplied (non-\c +.Dv NULL ) ,  +searches must also match the protocol. +.ne 1i +.Sh FILES +.Bl -tag -width /etc/services -compact +.It Pa /etc/services +.El +.Sh DIAGNOSTICS +Null pointer +(0) returned on +.Dv EOF +or error. +.Sh SEE ALSO +.Xr getprotoent 3 , +.Xr services 5 +.Sh HISTORY +The +.Fn getservent , +.Fn getservbyport , +.Fn getservbyname , +.Fn setservent , +and +.Fn endservent +functions appeared in  +.Bx 4.2 . +.Sh BUGS +These functions use static data storage; +if the data is needed for future use, it should be +copied before any subsequent calls overwrite it. +Expecting port numbers to fit in a 32 bit +quantity is probably naive. diff --git a/lib/libc/net/res_comp.c b/lib/libc/net/res_comp.c new file mode 100644 index 000000000000..66f37ba261cb --- /dev/null +++ b/lib/libc/net/res_comp.c @@ -0,0 +1,355 @@ +/*- + * Copyright (c) 1985, 1993 + *	The 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. + * - + * Portions Copyright (c) 1993 by Digital Equipment Corporation. + *  + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies, and that + * the name of Digital Equipment Corporation not be used in advertising or + * publicity pertaining to distribution of the document or software without + * specific, written prior permission. + *  + * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS.   IN NO EVENT SHALL DIGITAL EQUIPMENT + * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS + * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS + * SOFTWARE. + * - + * --Copyright-- + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static char sccsid[] = "@(#)res_comp.c	8.1 (Berkeley) 6/4/93"; +static char rcsid[] = "$Id: res_comp.c,v 4.9.1.1 1993/05/02 22:43:03 vixie Rel $"; +#endif /* LIBC_SCCS and not lint */ + +#include <sys/param.h> +#include <arpa/nameser.h> +#include <netinet/in.h> +#include <resolv.h> +#include <stdio.h> + +static int dn_find(); + +/* + * Expand compressed domain name 'comp_dn' to full domain name. + * 'msg' is a pointer to the begining of the message, + * 'eomorig' points to the first location after the message, + * 'exp_dn' is a pointer to a buffer of size 'length' for the result. + * Return size of compressed name or -1 if there was an error. + */ +dn_expand(msg, eomorig, comp_dn, exp_dn, length) +	const u_char *msg, *eomorig, *comp_dn; +	u_char *exp_dn; +	int length; +{ +	register u_char *cp, *dn; +	register int n, c; +	u_char *eom; +	int len = -1, checked = 0; + +	dn = exp_dn; +	cp = (u_char *)comp_dn; +	eom = exp_dn + length; +	/* +	 * fetch next label in domain name +	 */ +	while (n = *cp++) { +		/* +		 * Check for indirection +		 */ +		switch (n & INDIR_MASK) { +		case 0: +			if (dn != exp_dn) { +				if (dn >= eom) +					return (-1); +				*dn++ = '.'; +			} +			if (dn+n >= eom) +				return (-1); +			checked += n + 1; +			while (--n >= 0) { +				if ((c = *cp++) == '.') { +					if (dn + n + 2 >= eom) +						return (-1); +					*dn++ = '\\'; +				} +				*dn++ = c; +				if (cp >= eomorig)	/* out of range */ +					return(-1); +			} +			break; + +		case INDIR_MASK: +			if (len < 0) +				len = cp - comp_dn + 1; +			cp = (u_char *)msg + (((n & 0x3f) << 8) | (*cp & 0xff)); +			if (cp < msg || cp >= eomorig)	/* out of range */ +				return(-1); +			checked += 2; +			/* +			 * Check for loops in the compressed name; +			 * if we've looked at the whole message, +			 * there must be a loop. +			 */ +			if (checked >= eomorig - msg) +				return (-1); +			break; + +		default: +			return (-1);			/* flag error */ +		} +	} +	*dn = '\0'; +	if (len < 0) +		len = cp - comp_dn; +	return (len); +} + +/* + * Compress domain name 'exp_dn' into 'comp_dn'. + * Return the size of the compressed name or -1. + * 'length' is the size of the array pointed to by 'comp_dn'. + * 'dnptrs' is a list of pointers to previous compressed names. dnptrs[0] + * is a pointer to the beginning of the message. The list ends with NULL. + * 'lastdnptr' is a pointer to the end of the arrary pointed to + * by 'dnptrs'. Side effect is to update the list of pointers for + * labels inserted into the message as we compress the name. + * If 'dnptr' is NULL, we don't try to compress names. If 'lastdnptr' + * is NULL, we don't update the list. + */ +dn_comp(exp_dn, comp_dn, length, dnptrs, lastdnptr) +	const u_char *exp_dn; +	u_char *comp_dn, **dnptrs, **lastdnptr; +	int length; +{ +	register u_char *cp, *dn; +	register int c, l; +	u_char **cpp, **lpp, *sp, *eob; +	u_char *msg; + +	dn = (u_char *)exp_dn; +	cp = comp_dn; +	eob = cp + length; +	if (dnptrs != NULL) { +		if ((msg = *dnptrs++) != NULL) { +			for (cpp = dnptrs; *cpp != NULL; cpp++) +				; +			lpp = cpp;	/* end of list to search */ +		} +	} else +		msg = NULL; +	for (c = *dn++; c != '\0'; ) { +		/* look to see if we can use pointers */ +		if (msg != NULL) { +			if ((l = dn_find(dn-1, msg, dnptrs, lpp)) >= 0) { +				if (cp+1 >= eob) +					return (-1); +				*cp++ = (l >> 8) | INDIR_MASK; +				*cp++ = l % 256; +				return (cp - comp_dn); +			} +			/* not found, save it */ +			if (lastdnptr != NULL && cpp < lastdnptr-1) { +				*cpp++ = cp; +				*cpp = NULL; +			} +		} +		sp = cp++;	/* save ptr to length byte */ +		do { +			if (c == '.') { +				c = *dn++; +				break; +			} +			if (c == '\\') { +				if ((c = *dn++) == '\0') +					break; +			} +			if (cp >= eob) { +				if (msg != NULL) +					*lpp = NULL; +				return (-1); +			} +			*cp++ = c; +		} while ((c = *dn++) != '\0'); +		/* catch trailing '.'s but not '..' */ +		if ((l = cp - sp - 1) == 0 && c == '\0') { +			cp--; +			break; +		} +		if (l <= 0 || l > MAXLABEL) { +			if (msg != NULL) +				*lpp = NULL; +			return (-1); +		} +		*sp = l; +	} +	if (cp >= eob) { +		if (msg != NULL) +			*lpp = NULL; +		return (-1); +	} +	*cp++ = '\0'; +	return (cp - comp_dn); +} + +/* + * Skip over a compressed domain name. Return the size or -1. + */ +__dn_skipname(comp_dn, eom) +	const u_char *comp_dn, *eom; +{ +	register u_char *cp; +	register int n; + +	cp = (u_char *)comp_dn; +	while (cp < eom && (n = *cp++)) { +		/* +		 * check for indirection +		 */ +		switch (n & INDIR_MASK) { +		case 0:		/* normal case, n == len */ +			cp += n; +			continue; +		default:	/* illegal type */ +			return (-1); +		case INDIR_MASK:	/* indirection */ +			cp++; +		} +		break; +	} +	return (cp - comp_dn); +} + +/* + * Search for expanded name from a list of previously compressed names. + * Return the offset from msg if found or -1. + * dnptrs is the pointer to the first name on the list, + * not the pointer to the start of the message. + */ +static int +dn_find(exp_dn, msg, dnptrs, lastdnptr) +	u_char *exp_dn, *msg; +	u_char **dnptrs, **lastdnptr; +{ +	register u_char *dn, *cp, **cpp; +	register int n; +	u_char *sp; + +	for (cpp = dnptrs; cpp < lastdnptr; cpp++) { +		dn = exp_dn; +		sp = cp = *cpp; +		while (n = *cp++) { +			/* +			 * check for indirection +			 */ +			switch (n & INDIR_MASK) { +			case 0:		/* normal case, n == len */ +				while (--n >= 0) { +					if (*dn == '.') +						goto next; +					if (*dn == '\\') +						dn++; +					if (*dn++ != *cp++) +						goto next; +				} +				if ((n = *dn++) == '\0' && *cp == '\0') +					return (sp - msg); +				if (n == '.') +					continue; +				goto next; + +			default:	/* illegal type */ +				return (-1); + +			case INDIR_MASK:	/* indirection */ +				cp = msg + (((n & 0x3f) << 8) | *cp); +			} +		} +		if (*dn == '\0') +			return (sp - msg); +	next:	; +	} +	return (-1); +} + +/* + * Routines to insert/extract short/long's. Must account for byte + * order and non-alignment problems. This code at least has the + * advantage of being portable. + * + * used by sendmail. + */ + +u_short +_getshort(msgp) +	register u_char *msgp; +{ +	register u_int16_t u; + +	GETSHORT(u, msgp); +	return (u); +} + +u_int32_t +_getlong(msgp) +	register u_char *msgp; +{ +	register u_int32_t u; + +	GETLONG(u, msgp); +	return (u); +} + +void +#if defined(__STDC__) || defined(__cplusplus) +__putshort(register u_short s, register u_char *msgp) +#else +__putshort(s, msgp) +	register u_int16_t s; +	register u_char *msgp; +#endif +{ +	PUTSHORT(s, msgp); +} + +void +__putlong(l, msgp) +	register u_int32_t l; +	register u_char *msgp; +{ +	PUTLONG(l, msgp); +} diff --git a/lib/libc/net/res_debug.c b/lib/libc/net/res_debug.c new file mode 100644 index 000000000000..0bd882ad2d91 --- /dev/null +++ b/lib/libc/net/res_debug.c @@ -0,0 +1,739 @@ +/*- + * Copyright (c) 1985, 1990, 1993 + *	The 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. + * - + * Portions Copyright (c) 1993 by Digital Equipment Corporation. + *  + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies, and that + * the name of Digital Equipment Corporation not be used in advertising or + * publicity pertaining to distribution of the document or software without + * specific, written prior permission. + *  + * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS.   IN NO EVENT SHALL DIGITAL EQUIPMENT + * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS + * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS + * SOFTWARE. + * - + * --Copyright-- + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static char sccsid[] = "@(#)res_debug.c	8.1 (Berkeley) 6/4/93"; +#endif /* LIBC_SCCS and not lint */ + +#include <sys/param.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include <arpa/nameser.h> +#include <resolv.h> +#include <stdio.h> +#include <string.h> + +void __fp_query(); +char *__p_class(), *__p_time(), *__p_type(); +char *p_cdname(), *p_fqname(), *p_rr(); +static char *p_option __P((u_int32_t)); + +char *_res_opcodes[] = { +	"QUERY", +	"IQUERY", +	"CQUERYM", +	"CQUERYU", +	"4", +	"5", +	"6", +	"7", +	"8", +	"UPDATEA", +	"UPDATED", +	"UPDATEDA", +	"UPDATEM", +	"UPDATEMA", +	"ZONEINIT", +	"ZONEREF", +}; + +char *_res_resultcodes[] = { +	"NOERROR", +	"FORMERR", +	"SERVFAIL", +	"NXDOMAIN", +	"NOTIMP", +	"REFUSED", +	"6", +	"7", +	"8", +	"9", +	"10", +	"11", +	"12", +	"13", +	"14", +	"NOCHANGE", +}; + +static char retbuf[16]; + +static char * +dewks(wks) +	int wks; +{ +	switch (wks) { +	case 5: return("rje"); +	case 7: return("echo"); +	case 9: return("discard"); +	case 11: return("systat"); +	case 13: return("daytime"); +	case 15: return("netstat"); +	case 17: return("qotd"); +	case 19: return("chargen"); +	case 20: return("ftp-data"); +	case 21: return("ftp"); +	case 23: return("telnet"); +	case 25: return("smtp"); +	case 37: return("time"); +	case 39: return("rlp"); +	case 42: return("name"); +	case 43: return("whois"); +	case 53: return("domain"); +	case 57: return("apts"); +	case 59: return("apfs"); +	case 67: return("bootps"); +	case 68: return("bootpc"); +	case 69: return("tftp"); +	case 77: return("rje"); +	case 79: return("finger"); +	case 87: return("link"); +	case 95: return("supdup"); +	case 100: return("newacct"); +	case 101: return("hostnames"); +	case 102: return("iso-tsap"); +	case 103: return("x400"); +	case 104: return("x400-snd"); +	case 105: return("csnet-ns"); +	case 109: return("pop-2"); +	case 111: return("sunrpc"); +	case 113: return("auth"); +	case 115: return("sftp"); +	case 117: return("uucp-path"); +	case 119: return("nntp"); +	case 121: return("erpc"); +	case 123: return("ntp"); +	case 133: return("statsrv"); +	case 136: return("profile"); +	case 144: return("NeWS"); +	case 161: return("snmp"); +	case 162: return("snmp-trap"); +	case 170: return("print-srv"); +	default: (void) sprintf(retbuf, "%d", wks); return(retbuf); +	} +} + +static char * +deproto(protonum) +	int protonum; +{ +	switch (protonum) { +	case 1: return("icmp"); +	case 2: return("igmp"); +	case 3: return("ggp"); +	case 5: return("st"); +	case 6: return("tcp"); +	case 7: return("ucl"); +	case 8: return("egp"); +	case 9: return("igp"); +	case 11: return("nvp-II"); +	case 12: return("pup"); +	case 16: return("chaos"); +	case 17: return("udp"); +	default: (void) sprintf(retbuf, "%d", protonum); return(retbuf); +	} +} + +static char * +do_rrset(msg, cp, cnt, pflag, file, hs) +	int cnt, pflag; +	char *cp,*msg, *hs; +	FILE *file; +{ +	int n; +	int sflag; +	/* +	 * Print  answer records +	 */ +	sflag = (_res.pfcode & pflag); +	if (n = ntohs(cnt)) { +		if ((!_res.pfcode) || ((sflag) && (_res.pfcode & RES_PRF_HEAD1))) +			fprintf(file, hs); +		while (--n >= 0) { +			cp = p_rr(cp, msg, file); +			if ((cp-msg) > PACKETSZ) +				return (NULL); +		} +		if ((!_res.pfcode) || ((sflag) && (_res.pfcode & RES_PRF_HEAD1))) +			putc('\n', file); +	} +	return(cp); +} + +__p_query(msg) +	char *msg; +{ +	__fp_query(msg, stdout); +} + +/* + * Print the current options. + * This is intended to be primarily a debugging routine. + */ +void +__fp_resstat(statp, file) +	struct __res_state *statp; +	FILE *file; +{ +	int bit; + +	fprintf(file, ";; res options:"); +	if (!statp) +		statp = &_res; +	for (bit = 0;  bit < 32;  bit++) {	/* XXX 32 - bad assumption! */ +		if (statp->options & (1<<bit)) +			fprintf(file, " %s", p_option(1<<bit)); +	} +	putc('\n', file); +} + +/* + * Print the contents of a query. + * This is intended to be primarily a debugging routine. + */ +void +__fp_query(msg,file) +	char *msg; +	FILE *file; +{ +	register char *cp; +	register HEADER *hp; +	register int n; + +	/* +	 * Print header fields. +	 */ +	hp = (HEADER *)msg; +	cp = msg + sizeof(HEADER); +	if ((!_res.pfcode) || (_res.pfcode & RES_PRF_HEADX) || hp->rcode) { +		fprintf(file,";; ->>HEADER<<- opcode: %s, status: %s, id: %d", +			_res_opcodes[hp->opcode], +			_res_resultcodes[hp->rcode], +			ntohs(hp->id)); +		putc('\n', file); +	} +	putc(';', file); +	if ((!_res.pfcode) || (_res.pfcode & RES_PRF_HEAD2)) { +		fprintf(file,"; flags:"); +		if (hp->qr) +			fprintf(file," qr"); +		if (hp->aa) +			fprintf(file," aa"); +		if (hp->tc) +			fprintf(file," tc"); +		if (hp->rd) +			fprintf(file," rd"); +		if (hp->ra) +			fprintf(file," ra"); +		if (hp->pr) +			fprintf(file," pr"); +	} +	if ((!_res.pfcode) || (_res.pfcode & RES_PRF_HEAD1)) { +		fprintf(file,"; Ques: %d", ntohs(hp->qdcount)); +		fprintf(file,", Ans: %d", ntohs(hp->ancount)); +		fprintf(file,", Auth: %d", ntohs(hp->nscount)); +		fprintf(file,", Addit: %d\n", ntohs(hp->arcount)); +	} +#if 0 +	if (_res.pfcode & (RES_PRF_HEADX | RES_PRF_HEAD2 | RES_PRF_HEAD1)) { +		putc('\n',file); +	} +#endif +	/* +	 * Print question records. +	 */ +	if (n = ntohs(hp->qdcount)) { +		if ((!_res.pfcode) || (_res.pfcode & RES_PRF_QUES)) +			fprintf(file,";; QUESTIONS:\n"); +		while (--n >= 0) { +			fprintf(file,";;\t"); +			cp = p_cdname(cp, msg, file); +			if (cp == NULL) +				return; +			if ((!_res.pfcode) || (_res.pfcode & RES_PRF_QUES)) +				fprintf(file, ", type = %s", +					__p_type(_getshort(cp))); +			cp += sizeof(u_int16_t); +			if ((!_res.pfcode) || (_res.pfcode & RES_PRF_QUES)) +				fprintf(file, ", class = %s\n\n", +					__p_class(_getshort(cp))); +			cp += sizeof(u_int16_t); +		} +	} +	/* +	 * Print authoritative answer records +	 */ +	cp = do_rrset(msg, cp, hp->ancount, RES_PRF_ANS, file, +		      ";; ANSWERS:\n"); +	if (cp == NULL) +		return; + +	/* +	 * print name server records +	 */ +	cp = do_rrset(msg, cp, hp->nscount, RES_PRF_AUTH, file, +		      ";; AUTHORITY RECORDS:\n"); +	if (!cp) +		return; + +	/* +	 * print additional records +	 */ +	cp = do_rrset(msg, cp, hp->arcount, RES_PRF_ADD, file, +		      ";; ADDITIONAL RECORDS:\n"); +	if (!cp) +		return; +} + +char * +p_cdname(cp, msg, file) +	char *cp, *msg; +	FILE *file; +{ +	char name[MAXDNAME]; +	int n; + +	if ((n = dn_expand((u_char *)msg, (u_char *)msg + MAXCDNAME, +	    (u_char *)cp, (u_char *)name, sizeof(name))) < 0) +		return (NULL); +	if (name[0] == '\0') +		putc('.', file); +	else +		fputs(name, file); +	return (cp + n); +} + +char * +p_fqname(cp, msg, file) +	char *cp, *msg; +	FILE *file; +{ +	char name[MAXDNAME]; +	int n, len; + +	if ((n = dn_expand((u_char *)msg, (u_char *)msg + MAXCDNAME, +	    (u_char *)cp, (u_char *)name, sizeof(name))) < 0) +		return (NULL); +	if (name[0] == '\0') { +		putc('.', file); +	} else { +		fputs(name, file); +		if (name[strlen(name) - 1] != '.') +			putc('.', file); +	} +	return (cp + n); +} + +/* + * Print resource record fields in human readable form. + */ +char * +p_rr(cp, msg, file) +	char *cp, *msg; +	FILE *file; +{ +	int type, class, dlen, n, c; +	struct in_addr inaddr; +	char *cp1, *cp2; +	u_int32_t tmpttl, t; +	int lcnt; + +	if ((cp = p_fqname(cp, msg, file)) == NULL) +		return (NULL);			/* compression error */ +	type = _getshort(cp); +	cp += sizeof(u_int16_t); +	class = _getshort(cp); +	cp += sizeof(u_int16_t); +	tmpttl = _getlong(cp); +	cp += sizeof(u_int32_t); +	dlen = _getshort(cp); +	cp += sizeof(u_int16_t); +	cp1 = cp; +	if ((!_res.pfcode) || (_res.pfcode & RES_PRF_TTLID)) +		fprintf(file, "\t%lu", tmpttl); +	if ((!_res.pfcode) || (_res.pfcode & RES_PRF_CLASS)) +		fprintf(file, "\t%s", __p_class(class)); +	fprintf(file, "\t%s", __p_type(type)); +	/* +	 * Print type specific data, if appropriate +	 */ +	switch (type) { +	case T_A: +		switch (class) { +		case C_IN: +		case C_HS: +			bcopy(cp, (char *)&inaddr, sizeof(inaddr)); +			if (dlen == 4) { +				fprintf(file,"\t%s", inet_ntoa(inaddr)); +				cp += dlen; +			} else if (dlen == 7) { +				char *address; +				u_char protocol; +				u_short port; + +				address = inet_ntoa(inaddr); +				cp += sizeof(inaddr); +				protocol = *(u_char*)cp; +				cp += sizeof(u_char); +				port = _getshort(cp); +				cp += sizeof(u_int16_t); +				fprintf(file, "\t%s\t; proto %d, port %d", +					address, protocol, port); +			} +			break; +		default: +			cp += dlen; +		} +		break; +	case T_CNAME: +	case T_MB: +	case T_MG: +	case T_MR: +	case T_NS: +	case T_PTR: +		putc('\t', file); +		cp = p_fqname(cp, msg, file); +		break; + +	case T_HINFO: +		if (n = *cp++) { +			fprintf(file,"\t%.*s", n, cp); +			cp += n; +		} +		if (n = *cp++) { +			fprintf(file,"\t%.*s", n, cp); +			cp += n; +		} +		break; + +	case T_SOA: +		putc('\t', file); +		cp = p_fqname(cp, msg, file);	/* origin */ +		putc(' ', file); +		cp = p_fqname(cp, msg, file);	/* mail addr */ +		fputs(" (\n", file); +		t = _getlong(cp);  cp += sizeof(u_int32_t); +		fprintf(file,"\t\t\t%lu\t; serial\n", t); +		t = _getlong(cp);  cp += sizeof(u_int32_t); +		fprintf(file,"\t\t\t%lu\t; refresh (%s)\n", t, __p_time(t)); +		t = _getlong(cp);  cp += sizeof(u_int32_t); +		fprintf(file,"\t\t\t%lu\t; retry (%s)\n", t, __p_time(t)); +		t = _getlong(cp);  cp += sizeof(u_int32_t); +		fprintf(file,"\t\t\t%lu\t; expire (%s)\n", t, __p_time(t)); +		t = _getlong(cp);  cp += sizeof(u_int32_t); +		fprintf(file,"\t\t\t%lu )\t; minimum (%s)", t, __p_time(t)); +		break; + +	case T_MX: +		fprintf(file,"\t%d ", _getshort(cp)); +		cp += sizeof(u_int16_t); +		cp = p_fqname(cp, msg, file); +		break; + +  	case T_TXT: +		(void) fputs("\t\"", file); +		cp2 = cp1 + dlen; +		while (cp < cp2) { +			if (n = (unsigned char) *cp++) { +				for (c = n; c > 0 && cp < cp2; c--) +					if (*cp == '\n') { +					    (void) putc('\\', file); +					    (void) putc(*cp++, file); +					} else +					    (void) putc(*cp++, file); +			} +		} +		putc('"', file); +  		break; + +	case T_MINFO: +	case T_RP: +		putc('\t', file); +		cp = p_fqname(cp, msg, file); +		putc(' ', file); +		cp = p_fqname(cp, msg, file); +		break; + +	case T_UINFO: +		putc('\t', file); +		fputs(cp, file); +		cp += dlen; +		break; + +	case T_UID: +	case T_GID: +		if (dlen == 4) { +			fprintf(file,"\t%u", _getlong(cp)); +			cp += sizeof(int32_t); +		} +		break; + +	case T_WKS: +		if (dlen < sizeof(u_int32_t) + 1) +			break; +		bcopy(cp, (char *)&inaddr, sizeof(inaddr)); +		cp += sizeof(u_int32_t); +		fprintf(file, "\t%s %s ( ", +			inet_ntoa(inaddr), +			deproto((int) *cp)); +		cp += sizeof(u_char); +		n = 0; +		lcnt = 0; +		while (cp < cp1 + dlen) { +			c = *cp++; +			do { + 				if (c & 0200) { +					if (lcnt == 0) { +						fputs("\n\t\t\t", file); +						lcnt = 5; +					} +					fputs(dewks(n), file); +					putc(' ', file); +					lcnt--; +				} + 				c <<= 1; +			} while (++n & 07); +		} +		putc(')', file); +		break; + +#ifdef ALLOW_T_UNSPEC +	case T_UNSPEC: +		{ +			int NumBytes = 8; +			char *DataPtr; +			int i; + +			if (dlen < NumBytes) NumBytes = dlen; +			fprintf(file, "\tFirst %d bytes of hex data:", +				NumBytes); +			for (i = 0, DataPtr = cp; i < NumBytes; i++, DataPtr++) +				fprintf(file, " %x", *DataPtr); +			cp += dlen; +		} +		break; +#endif /* ALLOW_T_UNSPEC */ + +	default: +		fprintf(file,"\t?%d?", type); +		cp += dlen; +	} +#if 0 +	fprintf(file, "\t; dlen=%d, ttl %s\n", dlen, __p_time(tmpttl)); +#else +	putc('\n', file); +#endif +	if (cp - cp1 != dlen) { +		fprintf(file,";; packet size error (found %d, dlen was %d)\n", +			cp - cp1, dlen); +		cp = NULL; +	} +	return (cp); +} + +static	char nbuf[40]; + +/* + * Return a string for the type + */ +char * +__p_type(type) +	int type; +{ +	switch (type) { +	case T_A: +		return("A"); +	case T_NS:		/* authoritative server */ +		return("NS"); +	case T_CNAME:		/* canonical name */ +		return("CNAME"); +	case T_SOA:		/* start of authority zone */ +		return("SOA"); +	case T_MB:		/* mailbox domain name */ +		return("MB"); +	case T_MG:		/* mail group member */ +		return("MG"); +	case T_MR:		/* mail rename name */ +		return("MR"); +	case T_NULL:		/* null resource record */ +		return("NULL"); +	case T_WKS:		/* well known service */ +		return("WKS"); +	case T_PTR:		/* domain name pointer */ +		return("PTR"); +	case T_HINFO:		/* host information */ +		return("HINFO"); +	case T_MINFO:		/* mailbox information */ +		return("MINFO"); +	case T_MX:		/* mail routing info */ +		return("MX"); +	case T_TXT:		/* text */ +		return("TXT"); +	case T_RP:		/* responsible person */ +		return("RP"); +	case T_AXFR:		/* zone transfer */ +		return("AXFR"); +	case T_MAILB:		/* mail box */ +		return("MAILB"); +	case T_MAILA:		/* mail address */ +		return("MAILA"); +	case T_ANY:		/* matches any type */ +		return("ANY"); +	case T_UINFO: +		return("UINFO"); +	case T_UID: +		return("UID"); +	case T_GID: +		return("GID"); +#ifdef ALLOW_T_UNSPEC +	case T_UNSPEC: +		return("UNSPEC"); +#endif /* ALLOW_T_UNSPEC */ +	default: +		(void)sprintf(nbuf, "%d", type); +		return(nbuf); +	} +} + +/* + * Return a mnemonic for class + */ +char * +__p_class(class) +	int class; +{ + +	switch (class) { +	case C_IN:		/* internet class */ +		return("IN"); +	case C_HS:		/* hesiod class */ +		return("HS"); +	case C_ANY:		/* matches any class */ +		return("ANY"); +	default: +		(void)sprintf(nbuf, "%d", class); +		return(nbuf); +	} +} + +/* + * Return a mnemonic for an option + */ +static char * +p_option(option) +	u_int32_t option; +{ +	switch (option) { +	case RES_INIT:		return "init"; +	case RES_DEBUG:		return "debug"; +	case RES_AAONLY:	return "aaonly"; +	case RES_USEVC:		return "usevc"; +	case RES_PRIMARY:	return "primry"; +	case RES_IGNTC:		return "igntc"; +	case RES_RECURSE:	return "recurs"; +	case RES_DEFNAMES:	return "defnam"; +	case RES_STAYOPEN:	return "styopn"; +	case RES_DNSRCH:	return "dnsrch"; +	default:		sprintf(nbuf, "?0x%x?", option); return nbuf; +	} +} + +/* + * Return a mnemonic for a time to live + */ +char * +__p_time(value) +	u_int32_t value; +{ +	int secs, mins, hours, days; +	register char *p; + +	if (value == 0) { +		strcpy(nbuf, "0 secs"); +		return(nbuf); +	} + +	secs = value % 60; +	value /= 60; +	mins = value % 60; +	value /= 60; +	hours = value % 24; +	value /= 24; +	days = value; +	value = 0; + +#define	PLURALIZE(x)	x, (x == 1) ? "" : "s" +	p = nbuf; +	if (days) { +		(void)sprintf(p, "%d day%s", PLURALIZE(days)); +		while (*++p); +	} +	if (hours) { +		if (days) +			*p++ = ' '; +		(void)sprintf(p, "%d hour%s", PLURALIZE(hours)); +		while (*++p); +	} +	if (mins) { +		if (days || hours) +			*p++ = ' '; +		(void)sprintf(p, "%d min%s", PLURALIZE(mins)); +		while (*++p); +	} +	if (secs || ! (days || hours || mins)) { +		if (days || hours || mins) +			*p++ = ' '; +		(void)sprintf(p, "%d sec%s", PLURALIZE(secs)); +	} +	return(nbuf); +} diff --git a/lib/libc/net/res_init.c b/lib/libc/net/res_init.c new file mode 100644 index 000000000000..1e0fd05f68ea --- /dev/null +++ b/lib/libc/net/res_init.c @@ -0,0 +1,223 @@ +/*- + * Copyright (c) 1985, 1989, 1993 + *	The 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. + * - + * Portions Copyright (c) 1993 by Digital Equipment Corporation. + *  + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies, and that + * the name of Digital Equipment Corporation not be used in advertising or + * publicity pertaining to distribution of the document or software without + * specific, written prior permission. + *  + * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS.   IN NO EVENT SHALL DIGITAL EQUIPMENT + * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS + * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS + * SOFTWARE. + * - + * --Copyright-- + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static char sccsid[] = "@(#)res_init.c	8.1 (Berkeley) 6/7/93"; +static char rcsid[] = "$Id: res_init.c,v 4.9.1.1 1993/05/02 22:43:03 vixie Rel $"; +#endif /* LIBC_SCCS and not lint */ + +#include <sys/param.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include <arpa/nameser.h> +#include <resolv.h> +#include <unistd.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +/* + * Resolver state default settings + */ + +struct __res_state _res = { +	RES_TIMEOUT,               	/* retransmition time interval */ +	4,                         	/* number of times to retransmit */ +	RES_DEFAULT,			/* options flags */ +	1,                         	/* number of name servers */ +}; + +/* + * Set up default settings.  If the configuration file exist, the values + * there will have precedence.  Otherwise, the server address is set to + * INADDR_ANY and the default domain name comes from the gethostname(). + * + * The configuration file should only be used if you want to redefine your + * domain or run without a server on your machine. + * + * Return 0 if completes successfully, -1 on error + */ +res_init() +{ +	register FILE *fp; +	register char *cp, **pp; +	register int n; +	char buf[BUFSIZ]; +	int nserv = 0;    /* number of nameserver records read from file */ +	int haveenv = 0; +	int havesearch = 0; + +#ifdef USELOOPBACK +	_res.nsaddr.sin_addr = inet_makeaddr(IN_LOOPBACKNET, 1); +#else +	_res.nsaddr.sin_addr.s_addr = INADDR_ANY; +#endif +	_res.nsaddr.sin_family = AF_INET; +	_res.nsaddr.sin_port = htons(NAMESERVER_PORT); +	_res.nscount = 1; +	_res.pfcode = 0; + +	/* Allow user to override the local domain definition */ +	if ((cp = getenv("LOCALDOMAIN")) != NULL) { +		(void)strncpy(_res.defdname, cp, sizeof(_res.defdname)); +		if ((cp = strpbrk(_res.defdname, " \t\n")) != NULL) +			*cp = '\0'; +		haveenv++; +	} + +	if ((fp = fopen(_PATH_RESCONF, "r")) != NULL) { +	    /* read the config file */ +	    while (fgets(buf, sizeof(buf), fp) != NULL) { +		/* skip comments */ +		if ((*buf == ';') || (*buf == '#')) +			continue; +		/* read default domain name */ +		if (!strncmp(buf, "domain", sizeof("domain") - 1)) { +		    if (haveenv)	/* skip if have from environ */ +			    continue; +		    cp = buf + sizeof("domain") - 1; +		    while (*cp == ' ' || *cp == '\t') +			    cp++; +		    if ((*cp == '\0') || (*cp == '\n')) +			    continue; +		    (void)strncpy(_res.defdname, cp, +				  sizeof(_res.defdname) - 1); +		    if ((cp = strpbrk(_res.defdname, " \t\n")) != NULL) +			    *cp = '\0'; +		    havesearch = 0; +		    continue; +		} +		/* set search list */ +		if (!strncmp(buf, "search", sizeof("search") - 1)) { +		    if (haveenv)	/* skip if have from environ */ +			    continue; +		    cp = buf + sizeof("search") - 1; +		    while (*cp == ' ' || *cp == '\t') +			    cp++; +		    if ((*cp == '\0') || (*cp == '\n')) +			    continue; +		    (void)strncpy(_res.defdname, cp, +				  sizeof(_res.defdname) - 1); +		    if ((cp = strchr(_res.defdname, '\n')) != NULL) +			    *cp = '\0'; +		    /* +		     * Set search list to be blank-separated strings +		     * on rest of line. +		     */ +		    cp = _res.defdname; +		    pp = _res.dnsrch; +		    *pp++ = cp; +		    for (n = 0; *cp && pp < _res.dnsrch + MAXDNSRCH; cp++) { +			    if (*cp == ' ' || *cp == '\t') { +				    *cp = 0; +				    n = 1; +			    } else if (n) { +				    *pp++ = cp; +				    n = 0; +			    } +		    } +		    /* null terminate last domain if there are excess */ +		    while (*cp != '\0' && *cp != ' ' && *cp != '\t') +			    cp++; +		    *cp = '\0'; +		    *pp++ = 0; +		    havesearch = 1; +		    continue; +		} +		/* read nameservers to query */ +		if (!strncmp(buf, "nameserver", sizeof("nameserver") - 1) && +		   nserv < MAXNS) { +		   struct in_addr a; + +		    cp = buf + sizeof("nameserver") - 1; +		    while (*cp == ' ' || *cp == '\t') +			cp++; +		    if ((*cp != '\0') && (*cp != '\n') && inet_aton(cp, &a)) { +			_res.nsaddr_list[nserv].sin_addr = a; +			_res.nsaddr_list[nserv].sin_family = AF_INET; +			_res.nsaddr_list[nserv].sin_port = +				htons(NAMESERVER_PORT); +			nserv++; +		    } +		    continue; +		} +	    } +	    if (nserv > 1)  +		_res.nscount = nserv; +	    (void) fclose(fp); +	} +	if (_res.defdname[0] == 0) { +		if (gethostname(buf, sizeof(_res.defdname)) == 0 && +		   (cp = strchr(buf, '.'))) +			(void)strcpy(_res.defdname, cp + 1); +	} + +	/* find components of local domain that might be searched */ +	if (havesearch == 0) { +		pp = _res.dnsrch; +		*pp++ = _res.defdname; +		for (cp = _res.defdname, n = 0; *cp; cp++) +			if (*cp == '.') +				n++; +		cp = _res.defdname; +		for (; n >= LOCALDOMAINPARTS && pp < _res.dnsrch + MAXDFLSRCH; +		    n--) { +			cp = strchr(cp, '.'); +			*pp++ = ++cp; +		} +		*pp++ = 0; +	} +	_res.options |= RES_INIT; +	return (0); +} diff --git a/lib/libc/net/res_mkquery.c b/lib/libc/net/res_mkquery.c new file mode 100644 index 000000000000..a284562837f9 --- /dev/null +++ b/lib/libc/net/res_mkquery.c @@ -0,0 +1,230 @@ +/*- + * Copyright (c) 1985, 1993 + *	The 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. + * - + * Portions Copyright (c) 1993 by Digital Equipment Corporation. + *  + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies, and that + * the name of Digital Equipment Corporation not be used in advertising or + * publicity pertaining to distribution of the document or software without + * specific, written prior permission. + *  + * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS.   IN NO EVENT SHALL DIGITAL EQUIPMENT + * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS + * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS + * SOFTWARE. + * - + * --Copyright-- + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static char sccsid[] = "@(#)res_mkquery.c	8.1 (Berkeley) 6/4/93"; +static char rcsid[] = "$Id: res_mkquery.c,v 4.9.1.2 1993/05/17 10:00:01 vixie Exp $"; +#endif /* LIBC_SCCS and not lint */ + +#include <sys/param.h> +#include <netinet/in.h> +#include <arpa/nameser.h> +#include <resolv.h> +#include <stdio.h> +#include <string.h> + +/* + * Form all types of queries. + * Returns the size of the result or -1. + */ +res_mkquery(op, dname, class, type, data, datalen, newrr_in, buf, buflen) +	int op;			/* opcode of query */ +	const char *dname;		/* domain name */ +	int class, type;	/* class and type of query */ +	const char *data;		/* resource record data */ +	int datalen;		/* length of data */ +	const char *newrr_in;	/* new rr for modify or append */ +	char *buf;		/* buffer to put query */ +	int buflen;		/* size of buffer */ +{ +	register HEADER *hp; +	register char *cp; +	register int n; +	struct rrec *newrr = (struct rrec *) newrr_in; +	char *dnptrs[10], **dpp, **lastdnptr; + +#ifdef DEBUG +	if (_res.options & RES_DEBUG) +		printf(";; res_mkquery(%d, %s, %d, %d)\n", +		       op, dname, class, type); +#endif +	/* +	 * Initialize header fields. +	 */ +	if ((buf == NULL) || (buflen < sizeof(HEADER))) +		return(-1); +	bzero(buf, sizeof(HEADER)); +	hp = (HEADER *) buf; +	hp->id = htons(++_res.id); +	hp->opcode = op; +	hp->pr = (_res.options & RES_PRIMARY) != 0; +	hp->rd = (_res.options & RES_RECURSE) != 0; +	hp->rcode = NOERROR; +	cp = buf + sizeof(HEADER); +	buflen -= sizeof(HEADER); +	dpp = dnptrs; +	*dpp++ = buf; +	*dpp++ = NULL; +	lastdnptr = dnptrs + sizeof(dnptrs)/sizeof(dnptrs[0]); +	/* +	 * perform opcode specific processing +	 */ +	switch (op) { +	case QUERY: +		if ((buflen -= QFIXEDSZ) < 0) +			return(-1); +		if ((n = dn_comp((u_char *)dname, (u_char *)cp, buflen, +		    (u_char **)dnptrs, (u_char **)lastdnptr)) < 0) +			return (-1); +		cp += n; +		buflen -= n; +		__putshort(type, (u_char *)cp); +		cp += sizeof(u_int16_t); +		__putshort(class, (u_char *)cp); +		cp += sizeof(u_int16_t); +		hp->qdcount = htons(1); +		if (op == QUERY || data == NULL) +			break; +		/* +		 * Make an additional record for completion domain. +		 */ +		buflen -= RRFIXEDSZ; +		if ((n = dn_comp((u_char *)data, (u_char *)cp, buflen, +		    (u_char **)dnptrs, (u_char **)lastdnptr)) < 0) +			return (-1); +		cp += n; +		buflen -= n; +		__putshort(T_NULL, (u_char *)cp); +		cp += sizeof(u_int16_t); +		__putshort(class, (u_char *)cp); +		cp += sizeof(u_int16_t); +		__putlong(0, (u_char *)cp); +		cp += sizeof(u_int32_t); +		__putshort(0, (u_char *)cp); +		cp += sizeof(u_int16_t); +		hp->arcount = htons(1); +		break; + +	case IQUERY: +		/* +		 * Initialize answer section +		 */ +		if (buflen < 1 + RRFIXEDSZ + datalen) +			return (-1); +		*cp++ = '\0';	/* no domain name */ +		__putshort(type, (u_char *)cp); +		cp += sizeof(u_int16_t); +		__putshort(class, (u_char *)cp); +		cp += sizeof(u_int16_t); +		__putlong(0, (u_char *)cp); +		cp += sizeof(u_int32_t); +		__putshort(datalen, (u_char *)cp); +		cp += sizeof(u_int16_t); +		if (datalen) { +			bcopy(data, cp, datalen); +			cp += datalen; +		} +		hp->ancount = htons(1); +		break; + +#ifdef ALLOW_UPDATES +	/* +	 * For UPDATEM/UPDATEMA, do UPDATED/UPDATEDA followed by UPDATEA +	 * (Record to be modified is followed by its replacement in msg.) +	 */ +	case UPDATEM: +	case UPDATEMA: + +	case UPDATED: +		/* +		 * The res code for UPDATED and UPDATEDA is the same; user +		 * calls them differently: specifies data for UPDATED; server +		 * ignores data if specified for UPDATEDA. +		 */ +	case UPDATEDA: +		buflen -= RRFIXEDSZ + datalen; +		if ((n = dn_comp(dname, cp, buflen, dnptrs, lastdnptr)) < 0) +			return (-1); +		cp += n; +		__putshort(type, cp); +                cp += sizeof(u_int16_t); +                __putshort(class, cp); +                cp += sizeof(u_int16_t); +		__putlong(0, cp); +		cp += sizeof(u_int32_t); +		__putshort(datalen, cp); +                cp += sizeof(u_int16_t); +		if (datalen) { +			bcopy(data, cp, datalen); +			cp += datalen; +		} +		if ( (op == UPDATED) || (op == UPDATEDA) ) { +			hp->ancount = htons(0); +			break; +		} +		/* Else UPDATEM/UPDATEMA, so drop into code for UPDATEA */ + +	case UPDATEA:	/* Add new resource record */ +		buflen -= RRFIXEDSZ + datalen; +		if ((n = dn_comp(dname, cp, buflen, dnptrs, lastdnptr)) < 0) +			return (-1); +		cp += n; +		__putshort(newrr->r_type, cp); +                cp += sizeof(u_int16_t); +                __putshort(newrr->r_class, cp); +                cp += sizeof(u_int16_t); +		__putlong(0, cp); +		cp += sizeof(u_int32_t); +		__putshort(newrr->r_size, cp); +                cp += sizeof(u_int16_t); +		if (newrr->r_size) { +			bcopy(newrr->r_data, cp, newrr->r_size); +			cp += newrr->r_size; +		} +		hp->ancount = htons(0); +		break; + +#endif /* ALLOW_UPDATES */ +	} +	return (cp - buf); +} diff --git a/lib/libc/net/res_query.c b/lib/libc/net/res_query.c new file mode 100644 index 000000000000..4980af17b9d8 --- /dev/null +++ b/lib/libc/net/res_query.c @@ -0,0 +1,303 @@ +/*- + * Copyright (c) 1988, 1993 + *	The 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. + * - + * Portions Copyright (c) 1993 by Digital Equipment Corporation. + *  + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies, and that + * the name of Digital Equipment Corporation not be used in advertising or + * publicity pertaining to distribution of the document or software without + * specific, written prior permission. + *  + * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS.   IN NO EVENT SHALL DIGITAL EQUIPMENT + * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS + * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS + * SOFTWARE. + * - + * --Copyright-- + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static char sccsid[] = "@(#)res_query.c	8.1 (Berkeley) 6/4/93"; +static char rcsid[] = "$Id: res_query.c,v 1.1 1993/06/01 09:42:14 vixie Exp vixie $"; +#endif /* LIBC_SCCS and not lint */ + +#include <sys/param.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include <arpa/nameser.h> +#include <netdb.h> +#include <resolv.h> +#include <stdio.h> +#include <ctype.h> +#include <errno.h> +#include <stdlib.h> +#include <string.h> + +#if PACKETSZ > 1024 +#define MAXPACKET	PACKETSZ +#else +#define MAXPACKET	1024 +#endif + +int h_errno; + +/* + * Formulate a normal query, send, and await answer. + * Returned answer is placed in supplied buffer "answer". + * Perform preliminary check of answer, returning success only + * if no error is indicated and the answer count is nonzero. + * Return the size of the response on success, -1 on error. + * Error number is left in h_errno. + * Caller must parse answer and determine whether it answers the question. + */ +res_query(name, class, type, answer, anslen) +	char *name;		/* domain name */ +	int class, type;	/* class and type of query */ +	u_char *answer;		/* buffer to put answer */ +	int anslen;		/* size of answer buffer */ +{ +	char buf[MAXPACKET]; +	HEADER *hp; +	int n; + +	if ((_res.options & RES_INIT) == 0 && res_init() == -1) +		return (-1); +#ifdef DEBUG +	if (_res.options & RES_DEBUG) +		printf(";; res_query(%s, %d, %d)\n", name, class, type); +#endif +	n = res_mkquery(QUERY, name, class, type, (char *)NULL, 0, NULL, +	    buf, sizeof(buf)); + +	if (n <= 0) { +#ifdef DEBUG +		if (_res.options & RES_DEBUG) +			printf(";; res_query: mkquery failed\n"); +#endif +		h_errno = NO_RECOVERY; +		return (n); +	} +	n = res_send(buf, n, (char *)answer, anslen); +	if (n < 0) { +#ifdef DEBUG +		if (_res.options & RES_DEBUG) +			printf(";; res_query: send error\n"); +#endif +		h_errno = TRY_AGAIN; +		return(n); +	} + +	hp = (HEADER *) answer; +	if (hp->rcode != NOERROR || ntohs(hp->ancount) == 0) { +#ifdef DEBUG +		if (_res.options & RES_DEBUG) +			printf(";; rcode = %d, ancount=%d\n", hp->rcode, +			    ntohs(hp->ancount)); +#endif +		switch (hp->rcode) { +			case NXDOMAIN: +				h_errno = HOST_NOT_FOUND; +				break; +			case SERVFAIL: +				h_errno = TRY_AGAIN; +				break; +			case NOERROR: +				h_errno = NO_DATA; +				break; +			case FORMERR: +			case NOTIMP: +			case REFUSED: +			default: +				h_errno = NO_RECOVERY; +				break; +		} +		return (-1); +	} +	return(n); +} + +/* + * Formulate a normal query, send, and retrieve answer in supplied buffer. + * Return the size of the response on success, -1 on error. + * If enabled, implement search rules until answer or unrecoverable failure + * is detected.  Error number is left in h_errno. + * Only useful for queries in the same name hierarchy as the local host + * (not, for example, for host address-to-name lookups in domain in-addr.arpa). + */ +int +res_search(name, class, type, answer, anslen) +	char *name;		/* domain name */ +	int class, type;	/* class and type of query */ +	u_char *answer;		/* buffer to put answer */ +	int anslen;		/* size of answer */ +{ +	register char *cp, **domain; +	int n, ret, got_nodata = 0; +	char *__hostalias(); + +	if ((_res.options & RES_INIT) == 0 && res_init() == -1) +		return (-1); + +	errno = 0; +	h_errno = HOST_NOT_FOUND;	/* default, if we never query */ +	for (cp = name, n = 0; *cp; cp++) +		if (*cp == '.') +			n++; +	if (n == 0 && (cp = __hostalias(name))) +		return (res_query(cp, class, type, answer, anslen)); + +	/* +	 * We do at least one level of search if +	 *	- there is no dot and RES_DEFNAME is set, or +	 *	- there is at least one dot, there is no trailing dot, +	 *	  and RES_DNSRCH is set. +	 */ +	if ((n == 0 && _res.options & RES_DEFNAMES) || +	   (n != 0 && *--cp != '.' && _res.options & RES_DNSRCH)) +	     for (domain = _res.dnsrch; *domain; domain++) { +		ret = res_querydomain(name, *domain, class, type, +		    answer, anslen); +		if (ret > 0) +			return (ret); +		/* +		 * If no server present, give up. +		 * If name isn't found in this domain, +		 * keep trying higher domains in the search list +		 * (if that's enabled). +		 * On a NO_DATA error, keep trying, otherwise +		 * a wildcard entry of another type could keep us +		 * from finding this entry higher in the domain. +		 * If we get some other error (negative answer or +		 * server failure), then stop searching up, +		 * but try the input name below in case it's fully-qualified. +		 */ +		if (errno == ECONNREFUSED) { +			h_errno = TRY_AGAIN; +			return (-1); +		} +		if (h_errno == NO_DATA) +			got_nodata++; +		if ((h_errno != HOST_NOT_FOUND && h_errno != NO_DATA) || +		    (_res.options & RES_DNSRCH) == 0) +			break; +	} +	/* +	 * If the search/default failed, try the name as fully-qualified, +	 * but only if it contained at least one dot (even trailing). +	 * This is purely a heuristic; we assume that any reasonable query +	 * about a top-level domain (for servers, SOA, etc) will not use +	 * res_search. +	 */ +	if (n && (ret = res_querydomain(name, (char *)NULL, class, type, +	    answer, anslen)) > 0) +		return (ret); +	if (got_nodata) +		h_errno = NO_DATA; +	return (-1); +} + +/* + * Perform a call on res_query on the concatenation of name and domain, + * removing a trailing dot from name if domain is NULL. + */ +res_querydomain(name, domain, class, type, answer, anslen) +	char *name, *domain; +	int class, type;	/* class and type of query */ +	u_char *answer;		/* buffer to put answer */ +	int anslen;		/* size of answer */ +{ +	char nbuf[2*MAXDNAME+2]; +	char *longname = nbuf; +	int n; + +#ifdef DEBUG +	if (_res.options & RES_DEBUG) +		printf(";; res_querydomain(%s, %s, %d, %d)\n", +		    name, domain, class, type); +#endif +	if (domain == NULL) { +		/* +		 * Check for trailing '.'; +		 * copy without '.' if present. +		 */ +		n = strlen(name) - 1; +		if (name[n] == '.' && n < sizeof(nbuf) - 1) { +			bcopy(name, nbuf, n); +			nbuf[n] = '\0'; +		} else +			longname = name; +	} else +		(void)sprintf(nbuf, "%.*s.%.*s", +		    MAXDNAME, name, MAXDNAME, domain); + +	return (res_query(longname, class, type, answer, anslen)); +} + +char * +__hostalias(name) +	register const char *name; +{ +	register char *C1, *C2; +	FILE *fp; +	char *file, *getenv(), *strcpy(), *strncpy(); +	char buf[BUFSIZ]; +	static char abuf[MAXDNAME]; + +	file = getenv("HOSTALIASES"); +	if (file == NULL || (fp = fopen(file, "r")) == NULL) +		return (NULL); +	buf[sizeof(buf) - 1] = '\0'; +	while (fgets(buf, sizeof(buf), fp)) { +		for (C1 = buf; *C1 && !isspace(*C1); ++C1); +		if (!*C1) +			break; +		*C1 = '\0'; +		if (!strcasecmp(buf, name)) { +			while (isspace(*++C1)); +			if (!*C1) +				break; +			for (C2 = C1 + 1; *C2 && !isspace(*C2); ++C2); +			abuf[sizeof(abuf) - 1] = *C2 = '\0'; +			(void)strncpy(abuf, C1, sizeof(abuf) - 1); +			fclose(fp); +			return (abuf); +		} +	} +	fclose(fp); +	return (NULL); +} diff --git a/lib/libc/net/res_send.c b/lib/libc/net/res_send.c new file mode 100644 index 000000000000..5c80cf4d6869 --- /dev/null +++ b/lib/libc/net/res_send.c @@ -0,0 +1,468 @@ +/*- + * Copyright (c) 1985, 1989, 1993 + *	The 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. + * - + * Portions Copyright (c) 1993 by Digital Equipment Corporation. + *  + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies, and that + * the name of Digital Equipment Corporation not be used in advertising or + * publicity pertaining to distribution of the document or software without + * specific, written prior permission. + *  + * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS.   IN NO EVENT SHALL DIGITAL EQUIPMENT + * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS + * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS + * SOFTWARE. + * - + * --Copyright-- + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static char sccsid[] = "@(#)res_send.c	8.1 (Berkeley) 6/4/93"; +static char rcsid[] = "$Id: res_send.c,v 4.9.1.1 1993/05/02 22:43:03 vixie Rel $"; +#endif /* LIBC_SCCS and not lint */ + +/* + * Send query to name server and wait for reply. + */ + +#include <sys/param.h> +#include <sys/time.h> +#include <sys/socket.h> +#include <sys/uio.h> +#include <netinet/in.h> +#include <arpa/nameser.h> +#include <arpa/inet.h> +#include <stdio.h> +#include <errno.h> +#include <resolv.h> +#include <unistd.h> +#include <string.h> + +static int s = -1;	/* socket used for communications */ +static struct sockaddr no_addr; + +#ifndef FD_SET +#define	NFDBITS		32 +#define	FD_SETSIZE	32 +#define	FD_SET(n, p)	((p)->fds_bits[(n)/NFDBITS] |= (1 << ((n) % NFDBITS))) +#define	FD_CLR(n, p)	((p)->fds_bits[(n)/NFDBITS] &= ~(1 << ((n) % NFDBITS))) +#define	FD_ISSET(n, p)	((p)->fds_bits[(n)/NFDBITS] & (1 << ((n) % NFDBITS))) +#define FD_ZERO(p)	bzero((char *)(p), sizeof(*(p))) +#endif + +res_send(buf, buflen, answer, anslen) +	const char *buf; +	int buflen; +	char *answer; +	int anslen; +{ +	register int n; +	int try, v_circuit, resplen, ns; +	int gotsomewhere = 0, connected = 0; +	int connreset = 0; +	u_short id, len; +	char *cp; +	fd_set dsmask; +	struct timeval timeout; +	HEADER *hp = (HEADER *) buf; +	HEADER *anhp = (HEADER *) answer; +	u_int badns;		/* XXX NSMAX can't exceed #/bits per this */ +	struct iovec iov[2]; +	int terrno = ETIMEDOUT; +	char junk[512]; + +#ifdef DEBUG +	if ((_res.options & RES_DEBUG) || (_res.pfcode & RES_PRF_QUERY)) { +		printf(";; res_send()\n"); +		__p_query(buf); +	} +#endif +	if (!(_res.options & RES_INIT)) +		if (res_init() == -1) { +			return(-1); +		} +	v_circuit = (_res.options & RES_USEVC) || buflen > PACKETSZ; +	id = hp->id; +	badns = 0; +	/* +	 * Send request, RETRY times, or until successful +	 */ +	for (try = 0; try < _res.retry; try++) { +	    for (ns = 0; ns < _res.nscount; ns++) { +		if (badns & (1<<ns)) +			continue; +#ifdef DEBUG +		if (_res.options & RES_DEBUG) +			printf(";; Querying server (# %d) address = %s\n", +			       ns+1, +			       inet_ntoa(_res.nsaddr_list[ns].sin_addr)); +#endif +	usevc: +		if (v_circuit) { +			int truncated = 0; + +			/* +			 * Use virtual circuit; +			 * at most one attempt per server. +			 */ +			try = _res.retry; +			if (s < 0) { +				s = socket(AF_INET, SOCK_STREAM, 0); +				if (s < 0) { +					terrno = errno; +#ifdef DEBUG +					if (_res.options & RES_DEBUG) +					    perror("socket (vc) failed"); +#endif +					continue; +				} +				if (connect(s, +				    (struct sockaddr *)&(_res.nsaddr_list[ns]), +				    sizeof(struct sockaddr)) < 0) { +					terrno = errno; +#ifdef DEBUG +					if (_res.options & RES_DEBUG) +					    perror("connect failed"); +#endif +					(void) close(s); +					s = -1; +					continue; +				} +			} +			/* +			 * Send length & message +			 */ +			len = htons((u_short)buflen); +			iov[0].iov_base = (caddr_t)&len; +			iov[0].iov_len = sizeof(len); +			iov[1].iov_base = (char *)buf; +			iov[1].iov_len = buflen; +			if (writev(s, iov, 2) != sizeof(len) + buflen) { +				terrno = errno; +#ifdef DEBUG +				if (_res.options & RES_DEBUG) +					perror("write failed"); +#endif +				(void) close(s); +				s = -1; +				continue; +			} +			/* +			 * Receive length & response +			 */ +			cp = answer; +			len = sizeof(short); +			while (len != 0 && +			    (n = read(s, (char *)cp, (int)len)) > 0) { +				cp += n; +				len -= n; +			} +			if (n <= 0) { +				terrno = errno; +#ifdef DEBUG +				if (_res.options & RES_DEBUG) +					perror("read failed"); +#endif +				(void) close(s); +				s = -1; +				/* +				 * A long running process might get its TCP +				 * connection reset if the remote server was +				 * restarted.  Requery the server instead of +				 * trying a new one.  When there is only one +				 * server, this means that a query might work +				 * instead of failing.  We only allow one reset +				 * per query to prevent looping. +				 */ +				if (terrno == ECONNRESET && !connreset) { +					connreset = 1; +					ns--; +				} +				continue; +			} +			cp = answer; +			if ((resplen = ntohs(*(u_short *)cp)) > anslen) { +#ifdef DEBUG +				if (_res.options & RES_DEBUG) +					fprintf(stderr, +						";; response truncated\n"); +#endif +				len = anslen; +				truncated = 1; +			} else +				len = resplen; +			while (len != 0 && +			   (n = read(s, (char *)cp, (int)len)) > 0) { +				cp += n; +				len -= n; +			} +			if (n <= 0) { +				terrno = errno; +#ifdef DEBUG +				if (_res.options & RES_DEBUG) +					perror("read failed"); +#endif +				(void) close(s); +				s = -1; +				continue; +			} +			if (truncated) { +				/* +				 * Flush rest of answer +				 * so connection stays in synch. +				 */ +				anhp->tc = 1; +				len = resplen - anslen; +				while (len != 0) { +					n = (len > sizeof(junk) ? +					    sizeof(junk) : len); +					if ((n = read(s, junk, n)) > 0) +						len -= n; +					else +						break; +				} +			} +		} else { +			/* +			 * Use datagrams. +			 */ +			if (s < 0) { +				s = socket(AF_INET, SOCK_DGRAM, 0); +				if (s < 0) { +					terrno = errno; +#ifdef DEBUG +					if (_res.options & RES_DEBUG) +					    perror("socket (dg) failed"); +#endif +					continue; +				} +			} +			/* +			 * I'm tired of answering this question, so: +			 * On a 4.3BSD+ machine (client and server, +			 * actually), sending to a nameserver datagram +			 * port with no nameserver will cause an +			 * ICMP port unreachable message to be returned. +			 * If our datagram socket is "connected" to the +			 * server, we get an ECONNREFUSED error on the next +			 * socket operation, and select returns if the +			 * error message is received.  We can thus detect +			 * the absence of a nameserver without timing out. +			 * If we have sent queries to at least two servers, +			 * however, we don't want to remain connected, +			 * as we wish to receive answers from the first +			 * server to respond. +			 */ +			if (_res.nscount == 1 || (try == 0 && ns == 0)) { +				/* +				 * Don't use connect if we might +				 * still receive a response +				 * from another server. +				 */ +				if (connected == 0) { +					if (connect(s, +					    (struct sockaddr *) +					    &_res.nsaddr_list[ns], +					    sizeof(struct sockaddr)) < 0) { +#ifdef DEBUG +						if (_res.options & RES_DEBUG) +							perror("connect"); +#endif +						continue; +					} +					connected = 1; +				} +				if (send(s, buf, buflen, 0) != buflen) { +#ifdef DEBUG +					if (_res.options & RES_DEBUG) +						perror("send"); +#endif +					continue; +				} +			} else { +				/* +				 * Disconnect if we want to listen +				 * for responses from more than one server. +				 */ +				if (connected) { +					(void) connect(s, &no_addr, +					    sizeof(no_addr)); +					connected = 0; +				} +				if (sendto(s, buf, buflen, 0, +				    (struct sockaddr *)&_res.nsaddr_list[ns], +				    sizeof(struct sockaddr)) != buflen) { +#ifdef DEBUG +					if (_res.options & RES_DEBUG) +						perror("sendto"); +#endif +					continue; +				} +			} + +			/* +			 * Wait for reply +			 */ +			timeout.tv_sec = (_res.retrans << try); +			if (try > 0) +				timeout.tv_sec /= _res.nscount; +			if ((long) timeout.tv_sec <= 0) +				timeout.tv_sec = 1; +			timeout.tv_usec = 0; +wait: +			FD_ZERO(&dsmask); +			FD_SET(s, &dsmask); +			n = select(s+1, &dsmask, (fd_set *)NULL, +				(fd_set *)NULL, &timeout); +			if (n < 0) { +#ifdef DEBUG +				if (_res.options & RES_DEBUG) +					perror("select"); +#endif +				continue; +			} +			if (n == 0) { +				/* +				 * timeout +				 */ +#ifdef DEBUG +				if (_res.options & RES_DEBUG) +					printf(";; timeout\n"); +#endif +				gotsomewhere = 1; +				continue; +			} +			if ((resplen = recv(s, answer, anslen, 0)) <= 0) { +#ifdef DEBUG +				if (_res.options & RES_DEBUG) +					perror("recvfrom"); +#endif +				continue; +			} +			gotsomewhere = 1; +			if (id != anhp->id) { +				/* +				 * response from old query, ignore it +				 */ +#ifdef DEBUG +				if ((_res.options & RES_DEBUG) || +				    (_res.pfcode & RES_PRF_REPLY)) { +					printf(";; old answer:\n"); +					__p_query(answer); +				} +#endif +				goto wait; +			} +			if (anhp->rcode == SERVFAIL || anhp->rcode == NOTIMP || +			    anhp->rcode == REFUSED) { +#ifdef DEBUG +				if (_res.options & RES_DEBUG) { +					printf("server rejected query:\n"); +					__p_query(answer); +				} +#endif +				badns |= (1<<ns); +				continue; +			} +			if (!(_res.options & RES_IGNTC) && anhp->tc) { +				/* +				 * get rest of answer; +				 * use TCP with same server. +				 */ +#ifdef DEBUG +				if (_res.options & RES_DEBUG) +					printf(";; truncated answer\n"); +#endif +				(void) close(s); +				s = -1; +				v_circuit = 1; +				goto usevc; +			} +		} +#ifdef DEBUG +		if (_res.options & RES_DEBUG) +			printf(";; got answer:\n"); +		if ((_res.options & RES_DEBUG) || +		    (_res.pfcode & RES_PRF_REPLY)) +			__p_query(answer); +#endif +		/* +		 * If using virtual circuits, we assume that the first server +		 * is preferred * over the rest (i.e. it is on the local +		 * machine) and only keep that one open. +		 * If we have temporarily opened a virtual circuit, +		 * or if we haven't been asked to keep a socket open, +		 * close the socket. +		 */ +		if ((v_circuit && +		    ((_res.options & RES_USEVC) == 0 || ns != 0)) || +		    (_res.options & RES_STAYOPEN) == 0) { +			(void) close(s); +			s = -1; +		} +		return (resplen); +	   } +	} +	if (s >= 0) { +		(void) close(s); +		s = -1; +	} +	if (v_circuit == 0) +		if (gotsomewhere == 0) +			errno = ECONNREFUSED;	/* no nameservers found */ +		else +			errno = ETIMEDOUT;	/* no answer obtained */ +	else +		errno = terrno; +	return (-1); +} + +/* + * This routine is for closing the socket if a virtual circuit is used and + * the program wants to close it.  This provides support for endhostent() + * which expects to close the socket. + * + * This routine is not expected to be user visible. + */ +_res_close() +{ +	if (s != -1) { +		(void) close(s); +		s = -1; +	} +} diff --git a/lib/libc/net/sethostent.c b/lib/libc/net/sethostent.c new file mode 100644 index 000000000000..dbc6e204060e --- /dev/null +++ b/lib/libc/net/sethostent.c @@ -0,0 +1,56 @@ +/* + * Copyright (c) 1985, 1993 + *	The 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. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static char sccsid[] = "@(#)sethostent.c	8.1 (Berkeley) 6/4/93"; +#endif /* LIBC_SCCS and not lint */ + +#include <sys/param.h> +#include <netinet/in.h> +#include <arpa/nameser.h> +#include <netdb.h> +#include <resolv.h> + +void +sethostent(stayopen) +{ +	if (stayopen) +		_res.options |= RES_STAYOPEN | RES_USEVC; +} + +void +endhostent() +{ +	_res.options &= ~(RES_STAYOPEN | RES_USEVC); +	_res_close(); +} diff --git a/lib/libc/stdlib/free.3 b/lib/libc/stdlib/free.3 new file mode 100644 index 000000000000..17d99eb97c3b --- /dev/null +++ b/lib/libc/stdlib/free.3 @@ -0,0 +1,81 @@ +.\" Copyright (c) 1991, 1993 +.\"	The Regents of the University of California.  All rights reserved. +.\" +.\" This code is derived from software contributed to Berkeley by +.\" the American National Standards Committee X3, on Information +.\" Processing Systems. +.\" +.\" 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. +.\" +.\"     @(#)free.3	8.1 (Berkeley) 6/4/93 +.\" +.Dd June 4, 1993 +.Dt FREE 3 +.Os +.Sh NAME +.Nm free +.Nd free up memory allocated with malloc, calloc or realloc +.Sh SYNOPSIS +.Fd #include <stdlib.h> +.Ft void +.Fn free "void *ptr" +.Sh DESCRIPTION +The +.Fn free +function causes the space pointed to by +.Fa ptr +to be deallocated, that is, made available +for further allocation. +If +.Fa ptr +is a null pointer, no action occurs. +Otherwise, if the argument does not match a pointer earlier +returned by the +.Xr calloc , +.Xr malloc , +or +.Xr realloc +function, or if the space has been deallocated by a call to +.Fn free +or +.Xr realloc , +general havoc may occur. +.Sh RETURN VALUES +The +.Fn free +function returns no value. +.Sh SEE ALSO +.Xr calloc 3 , +.Xr malloc 3 , +.Xr realloc 3 +.Sh STANDARDS +The +.Fn free +function conforms to +.St -ansiC . diff --git a/lib/libc/stdlib/realloc.3 b/lib/libc/stdlib/realloc.3 new file mode 100644 index 000000000000..903825cbb96f --- /dev/null +++ b/lib/libc/stdlib/realloc.3 @@ -0,0 +1,99 @@ +.\" Copyright (c) 1991, 1993 +.\"	The 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. +.\" +.\"     @(#)realloc.3	8.2 (Berkeley) 4/19/94 +.\" +.Dd April 19, 1994 +.Dt REALLOC 3 +.Os +.Sh NAME +.Nm realloc +.Nd reallocation of memory function +.Sh SYNOPSIS +.Fd #include <stdlib.h> +.Ft void * +.Fn realloc "void *ptr" "size_t size" +.Sh DESCRIPTION +The +.Fn realloc +function changes the size of the object pointed to by +.Fa ptr +to the size specified by +.Fa size . +The contents of the object are unchanged up to the lesser +of the new and old sizes. +If the new size is larger, the value of the newly allocated portion +of the object is indeterminate. +If +.Fa ptr +is a null pointer, the +.Fn realloc +function behaves like the +.Xr malloc 3 +function for the specified size. +Otherwise, if +.Fa ptr +does not match a pointer earlier returned by the +.Xr calloc 3 , +.Xr malloc 3 , +or  +.Fn realloc +function, or if the space has been deallocated +by a call to the +.Xr free +or +.Fn realloc +function, unpredictable and usually detrimental +behavior will occur. +If the space cannot be allocated, the object  +pointed to by +.Fa ptr +is unchanged. +If +.Fa size +is zero and +.Fa ptr +is not a null pointer, the object it points to is freed. +.Pp +The +.Fn realloc +function returns either a null pointer or a pointer +to the possibly moved allocated space. +.Sh SEE ALSO +.Xr alloca 3 , +.Xr calloc 3 , +.Xr free 3 , +.Xr malloc 3 , +.Sh STANDARDS +The +.Fn realloc +function conforms to +.St -ansiC . diff --git a/lib/libc/string/strftime.3 b/lib/libc/string/strftime.3 new file mode 100644 index 000000000000..3da35a1c4460 --- /dev/null +++ b/lib/libc/string/strftime.3 @@ -0,0 +1,186 @@ +.\" Copyright (c) 1989, 1991, 1993 +.\"	The Regents of the University of California.  All rights reserved. +.\" +.\" This code is derived from software contributed to Berkeley by +.\" the American National Standards Committee X3, on Information +.\" Processing Systems. +.\" +.\" 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. +.\" +.\"     @(#)strftime.3	8.1 (Berkeley) 6/4/93 +.\" +.Dd June 4, 1993 +.Dt STRFTIME 3 +.Os +.Sh NAME +.Nm strftime +.Nd format date and time +.Sh SYNOPSIS +.Fd #include <sys/types.h> +.Fd #include <time.h> +.Fd #include <string.h> +.Ft size_t +.Fn strftime "char *buf" "size_t maxsize" "const char *format" "const struct tm *timeptr" +.Sh DESCRIPTION +The +.Fn strftime +function formats the information from +.Fa timeptr +into the buffer +.Fa buf +according to the string pointed to by +.Fa format . +.Pp +The +.Fa format +string consists of zero or more conversion specifications and +ordinary characters. +All ordinary characters are copied directly into the buffer. +A conversion specification consists of a percent sign +.Dq Ql % +and one other character. +.Pp +No more than +.Fa maxsize +characters will be placed into the array. +If the total number of resulting characters, including the terminating +null character, is not more than +.Fa maxsize , +.Fn strftime +returns the number of characters in the array, not counting the +terminating null. +Otherwise, zero is returned. +.Pp +Each conversion specification is replaced by the characters as +follows which are then copied into the buffer. +.Bl -tag -width "xxxx" +.It Cm \&%A +is replaced by the full weekday name. +.It Cm %a +is replaced by the abbreviated weekday name, where the abbreviation +is the first three characters. +.It Cm \&%B +is replaced by the full month name. +.It Cm %b  or  %h +is replaced by the abbreviated month name, where the abbreviation is +the first three characters. +.It Cm \&%C +is equivalent to +.Dq Li %a %b %e %H:%M:%S %Y +(the format produced by +.Xr asctime 3 . +.It Cm %c +is equivalent to +.Dq Li %m/%d/%y . +.It Cm \&%D +is replaced by the date in the format +.Dq Ql mm/dd/yy . +.It Cm %d +is replaced by the day of the month as a decimal number (01-31). +.It Cm %e +is replaced by the day of month as a decimal number (1-31); single +digits are preceded by a blank. +.It Cm \&%H +is replaced by the hour (24-hour clock) as a decimal number (00-23). +.It Cm \&%I +is replaced by the hour (12-hour clock) as a decimal number (01-12). +.It Cm %j +is replaced by the day of the year as a decimal number (001-366). +.It Cm %k +is replaced by the hour (24-hour clock) as a decimal number (0-23); +single digits are preceded by a blank. +.It Cm %l +is replaced by the hour (12-hour clock) as a decimal number (1-12); +single digits are preceded by a blank. +.It Cm \&%M +is replaced by the minute as a decimal number (00-59). +.It Cm %m +is replaced by the month as a decimal number (01-12). +.It Cm %n +is replaced by a newline. +.It Cm %p +is replaced by either +.Dq Tn AM +or +.Dq Tn PM +as appropriate. +.It Cm \&%R +is equivalent to +.Dq Li %H:%M +.It Cm %r +is equivalent to +.Dq Li %I:%M:%S %p . +.It Cm %t +is replaced by a tab. +.It Cm \&%S +is replaced by the second as a decimal number (00-60). +.It Cm %s +is replaced by the number of seconds since the Epoch, UCT (see +.Xr mktime 3 ) . +.It Cm \&%T No or Cm \&%X +is equivalent to +.Dq Li %H:%M:%S . +.It Cm \&%U +is replaced by the week number of the year (Sunday as the first day of +the week) as a decimal number (00-53). +.It Cm \&%W +is replaced by the week number of the year (Monday as the first day of +the week) as a decimal number (00-53). +.It Cm %w +is replaced by the weekday (Sunday as the first day of the week) +as a decimal number (0-6). +.It Cm %x +is equivalent to +.Dq Li %m/%d/%y %H:%M:%S . +.It Cm \&%Y +is replaced by the year with century as a decimal number. +.It Cm %y +is replaced by the year without century as a decimal number (00-99). +.It Cm \&%Z +is replaced by the time zone name. +.It Cm %% +is replaced by +.Ql % . +.El +.Sh SEE ALSO +.Xr date 1 , +.Xr ctime 3 , +.Xr printf 1 , +.Xr printf 3 +.Sh STANDARDS +The +.Fn strftime +function +conforms to +.St -ansiC . +The +.Ql %s +conversion specification is an extension. +.Sh BUGS +There is no conversion specification for the phase of the moon. diff --git a/lib/libc/string/strftime.c b/lib/libc/string/strftime.c new file mode 100644 index 000000000000..b39aeeb9917a --- /dev/null +++ b/lib/libc/string/strftime.c @@ -0,0 +1,292 @@ +/* + * Copyright (c) 1989, 1993 + *	The 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. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static char sccsid[] = "@(#)strftime.c	8.1 (Berkeley) 6/4/93"; +#endif /* LIBC_SCCS and not lint */ + +#include <sys/types.h> +#include <sys/time.h> +#include <tzfile.h> +#include <string.h> + +static char *afmt[] = { +	"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", +}; +static char *Afmt[] = { +	"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", +	"Saturday", +}; +static char *bfmt[] = { +	"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", +	"Oct", "Nov", "Dec", +}; +static char *Bfmt[] = { +	"January", "February", "March", "April", "May", "June", "July", +	"August", "September", "October", "November", "December", +}; + +static size_t gsize; +static char *pt; +static int _add __P((char *)); +static int _conv __P((int, int, int)); +static int _secs __P((const struct tm *)); +static size_t _fmt __P((const char *, const struct tm *)); + +size_t +strftime(s, maxsize, format, t) +	char *s; +	size_t maxsize; +	const char *format; +	const struct tm *t; +{ + +	pt = s; +	if ((gsize = maxsize) < 1) +		return(0); +	if (_fmt(format, t)) { +		*pt = '\0'; +		return(maxsize - gsize); +	} +	return(0); +} + +static size_t +_fmt(format, t) +	register const char *format; +	const struct tm *t; +{ +	for (; *format; ++format) { +		if (*format == '%') +			switch(*++format) { +			case '\0': +				--format; +				break; +			case 'A': +				if (t->tm_wday < 0 || t->tm_wday > 6) +					return(0); +				if (!_add(Afmt[t->tm_wday])) +					return(0); +				continue; +			case 'a': +				if (t->tm_wday < 0 || t->tm_wday > 6) +					return(0); +				if (!_add(afmt[t->tm_wday])) +					return(0); +				continue; +			case 'B': +				if (t->tm_mon < 0 || t->tm_mon > 11) +					return(0); +				if (!_add(Bfmt[t->tm_mon])) +					return(0); +				continue; +			case 'b': +			case 'h': +				if (t->tm_mon < 0 || t->tm_mon > 11) +					return(0); +				if (!_add(bfmt[t->tm_mon])) +					return(0); +				continue; +			case 'C': +				if (!_fmt("%a %b %e %H:%M:%S %Y", t)) +					return(0); +				continue; +			case 'c': +				if (!_fmt("%m/%d/%y %H:%M:%S", t)) +					return(0); +				continue; +			case 'D': +				if (!_fmt("%m/%d/%y", t)) +					return(0); +				continue; +			case 'd': +				if (!_conv(t->tm_mday, 2, '0')) +					return(0); +				continue; +			case 'e': +				if (!_conv(t->tm_mday, 2, ' ')) +					return(0); +				continue; +			case 'H': +				if (!_conv(t->tm_hour, 2, '0')) +					return(0); +				continue; +			case 'I': +				if (!_conv(t->tm_hour % 12 ? +				    t->tm_hour % 12 : 12, 2, '0')) +					return(0); +				continue; +			case 'j': +				if (!_conv(t->tm_yday + 1, 3, '0')) +					return(0); +				continue; +			case 'k': +				if (!_conv(t->tm_hour, 2, ' ')) +					return(0); +				continue; +			case 'l': +				if (!_conv(t->tm_hour % 12 ? +				    t->tm_hour % 12 : 12, 2, ' ')) +					return(0); +				continue; +			case 'M': +				if (!_conv(t->tm_min, 2, '0')) +					return(0); +				continue; +			case 'm': +				if (!_conv(t->tm_mon + 1, 2, '0')) +					return(0); +				continue; +			case 'n': +				if (!_add("\n")) +					return(0); +				continue; +			case 'p': +				if (!_add(t->tm_hour >= 12 ? "PM" : "AM")) +					return(0); +				continue; +			case 'R': +				if (!_fmt("%H:%M", t)) +					return(0); +				continue; +			case 'r': +				if (!_fmt("%I:%M:%S %p", t)) +					return(0); +				continue; +			case 'S': +				if (!_conv(t->tm_sec, 2, '0')) +					return(0); +				continue; +			case 's': +				if (!_secs(t)) +					return(0); +				continue; +			case 'T': +			case 'X': +				if (!_fmt("%H:%M:%S", t)) +					return(0); +				continue; +			case 't': +				if (!_add("\t")) +					return(0); +				continue; +			case 'U': +				if (!_conv((t->tm_yday + 7 - t->tm_wday) / 7, +				    2, '0')) +					return(0); +				continue; +			case 'W': +				if (!_conv((t->tm_yday + 7 - +				    (t->tm_wday ? (t->tm_wday - 1) : 6)) +				    / 7, 2, '0')) +					return(0); +				continue; +			case 'w': +				if (!_conv(t->tm_wday, 1, '0')) +					return(0); +				continue; +			case 'x': +				if (!_fmt("%m/%d/%y", t)) +					return(0); +				continue; +			case 'y': +				if (!_conv((t->tm_year + TM_YEAR_BASE) +				    % 100, 2, '0')) +					return(0); +				continue; +			case 'Y': +				if (!_conv(t->tm_year + TM_YEAR_BASE, 4, '0')) +					return(0); +				continue; +			case 'Z': +				if (!t->tm_zone || !_add(t->tm_zone)) +					return(0); +				continue; +			case '%': +			/* +			 * X311J/88-090 (4.12.3.5): if conversion char is +			 * undefined, behavior is undefined.  Print out the +			 * character itself as printf(3) does. +			 */ +			default: +				break; +		} +		if (!gsize--) +			return(0); +		*pt++ = *format; +	} +	return(gsize); +} + +static int +_secs(t) +	const struct tm *t; +{ +	static char buf[15]; +	register time_t s; +	register char *p; +	struct tm tmp; + +	/* Make a copy, mktime(3) modifies the tm struct. */ +	tmp = *t; +	s = mktime(&tmp); +	for (p = buf + sizeof(buf) - 2; s > 0 && p > buf; s /= 10) +		*p-- = s % 10 + '0'; +	return(_add(++p)); +} + +static int +_conv(n, digits, pad) +	int n, digits, pad; +{ +	static char buf[10]; +	register char *p; + +	for (p = buf + sizeof(buf) - 2; n > 0 && p > buf; n /= 10, --digits) +		*p-- = n % 10 + '0'; +	while (p > buf && digits-- > 0) +		*p-- = pad; +	return(_add(++p)); +} + +static int +_add(str) +	register char *str; +{ +	for (;; ++pt, --gsize) { +		if (!gsize) +			return(0); +		if (!(*pt = *str++)) +			return(1); +	} +} diff --git a/lib/libcompat/regexp/regexp.h b/lib/libcompat/regexp/regexp.h new file mode 100644 index 000000000000..73d6bf412424 --- /dev/null +++ b/lib/libcompat/regexp/regexp.h @@ -0,0 +1,21 @@ +/* + * Definitions etc. for regexp(3) routines. + * + * Caveat:  this is V8 regexp(3) [actually, a reimplementation thereof], + * not the System V one. + */ +#define NSUBEXP  10 +typedef struct regexp { +	char *startp[NSUBEXP]; +	char *endp[NSUBEXP]; +	char regstart;		/* Internal use only. */ +	char reganch;		/* Internal use only. */ +	char *regmust;		/* Internal use only. */ +	int regmlen;		/* Internal use only. */ +	char program[1];	/* Unwarranted chumminess with compiler. */ +} regexp; + +extern regexp *regcomp(); +extern int regexec(); +extern void regsub(); +extern void regerror(); diff --git a/lib/libcurses/PSD.doc/Makefile b/lib/libcurses/PSD.doc/Makefile new file mode 100644 index 000000000000..a09c460d3559 --- /dev/null +++ b/lib/libcurses/PSD.doc/Makefile @@ -0,0 +1,35 @@ +#	@(#)Makefile	8.2 (Berkeley) 5/23/94 + +DIR=	psd/19.curses +SRCS=	Master +MACROS=	-me + +CLEANFILES+=win_st.gr twinkle1.gr twinkle2.gr life.gr intro.2.tbl appen.A.tbl \ +	ex1.gr ex2.gr + +.SUFFIXES: +.SUFFIXES: .c .gr + +# +# this section formats C input source into nice troffable (or nroffable) +# versions.  It uses the capabilites of "vgrind", which sets keywords in +# bold font, and comments in italics. +# + +# Don't re-run vgrind unless you want to patch the output files. +VFONT=	/usr/libexec/vfontedpr +.c.gr: +	${VFONT} $*.c | grep -v "^'wh" > $*.gr + +paper.ps: ${SRCS} +	soelim ${SRCS} | ${ROFF} > ${.TARGET} + +Master: twinkle1.gr ex1.gr ex2.gr fns.doc intro.5 intro.2.tbl intro.0 intro.1 \ +	intro.3 intro.4 intro.6 macros c_macros + +intro.2.tbl: intro.2 +	${TBL} intro.2 > intro.2.tbl + +.include <bsd.doc.mk> + + diff --git a/lib/libcurses/PSD.doc/Master b/lib/libcurses/PSD.doc/Master new file mode 100644 index 000000000000..12db62b9bfaf --- /dev/null +++ b/lib/libcurses/PSD.doc/Master @@ -0,0 +1,54 @@ +.\" Copyright (c) 1980, 1993 +.\"	The 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. +.\" +.\"	@(#)Master	8.2 (Berkeley) 5/24/94 +.\" +.ds Ln Screen Package +.so macros +.so c_macros +.so intro.0 +.pn 3 +.bp +.so intro.1 +.so intro.2.tbl +.so intro.3 +.so intro.4 +.so intro.5 +.so intro.6 +.bp +.so appen.A +.pn 2 +.oh '\*(Ln''PSD:19-%' +.eh 'PSD:19-%''\*(Ln' +.bp +.bi Contents +.sp +.xp diff --git a/lib/libcurses/PSD.doc/fns.doc b/lib/libcurses/PSD.doc/fns.doc new file mode 100644 index 000000000000..0fa89abd3f74 --- /dev/null +++ b/lib/libcurses/PSD.doc/fns.doc @@ -0,0 +1,799 @@ +.\" Copyright (c) 1992, 1993 +.\"	The 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. +.\" +.\"     @(#)fns.doc	8.2 (Berkeley) 6/1/94 +.\" +.Ds +.Fn addch "char ch" \(dg +.De +Add the character +.Vn ch +on the window +at the current \*y. +If the character is a newline +(\'\en\') +the line will be cleared to the end, +and the current \*y will be changed to the +beginning off the next line +if newline mapping is on, +or to the next line at the same x co-ordinate +if it is off. +A return +(\'\er\') +will move to the beginning of the line on the window. +Tabs +(\'\et\') +will be expanded into spaces +in the normal tabstop positions of +every eight characters. +\*(Es +.Ds +.Fn addstr "char *str" \(dg +.De +Add the string pointed to by +.Vn str +on the window at the current \*y. +\*(Es +In this case, it will put on as much as it can. +.Ds +.Fn baudrate "" \(dg +.De +Returns the output baud rate of the terminal. +This is a system dependent constant +(defined in +.b <sys/tty.h> +on BSD systems, +which is included by +.b <curses.h> ). +.Ds +.Fn box "WINDOW win" "char vert" "char hor" +.De +.Pp +Draws a box around the window using +.Vn vert +as the character for drawing the vertical sides, and +.Vn hor +for drawing the horizontal lines. +If scrolling is not allowed, +and the window encompasses the lower right-hand corner of the terminal, +the corners are left blank to avoid a scroll. +.Ds +.Fn cbreak "" \(dg +.De +Set or the terminal to cbreak mode. +.Ds +.Fn clear "" \(dg +.De +Resets the entire window to blanks. +If +.Vn win +is a screen, +this sets the clear flag, +which will cause a clear-screen sequence to be sent +on the next +.Fn refresh +call. +This also moves the current \*y +to (0\*,0). +.Ds +.Fn clearok "WINDOW *scr" "int boolf" \(dg +.De +Sets the clear flag for the screen +.Vn scr . +If +.Vn boolf +is non-zero, +this will force a clear-screen to be printed on the next +.Fn refresh , +or stop it from doing so if +.Vn boolf +is 0. +This only works on screens, +and, +unlike +.Fn clear , +does not alter the contents of the screen. +If +.Vn scr +is +.Vn curscr , +the next +.Fn refresh +call will cause a clear-screen, +even if the window passed to +.Fn refresh +is not a screen. +.Ds +.Fn clrtobot "" \(dg +.De +Wipes the window clear from the current \*y to the bottom. +This does not force a clear-screen sequence on the next refresh +under any circumstances. +\*(Nm +.Ds +.Fn clrtoeol "" \(dg +.De +Wipes the window clear from the current \*y to the end of the line. +\*(Nm +.Ds +.Fn crmode "" \(dg +.De +Identical to  +.Fn cbreak . +The misnamed macro +.Fn crmode +and +.Fn nocrmode +is retained for backwards compatibility +with ealier versions of the library. +.Ds +.Fn delch "" +.De +Delete the character at the current \*y. +Each character after it on the line shifts to the left, +and the last character becomes blank. +.Ds +.Fn deleteln "" +.De +Delete the current line. +Every line below the current one will move up, +and the bottom line will become blank. +The current \*y will remain unchanged. +.Ds +.Fn delwin "WINDOW *win" +.De +Deletes the window from existence. +All resources are freed for future use by +.b calloc (3). +If a window has a +.Fn subwin +allocated window inside of it, +deleting the outer window +the subwindow is not affected, +even though this does invalidate it. +Therefore, +subwindows should be deleted before their +outer windows are. +.Ds +.Fn echo "" \(dg +.De +Sets the terminal to echo characters. +.Ds +.Fn endwin "" +.De +Finish up window routines before exit. +This restores the terminal to the state it was before +.Fn initscr +(or +.Fn gettmode +and +.Fn setterm ) +was called. +It should always be called before exiting and before the final calls to  +.Fn delwin . +It does not exit. +This is especially useful for resetting tty stats +when trapping rubouts via +.b signal (2). +.Ds +.Fn erase "" \(dg +.De +Erases the window to blanks without setting the clear flag. +This is analagous to +.Fn clear , +except that it never causes a clear-screen sequence to be generated +on a +.Fn refresh . +\*(Nm +.Ds +.Fn erasechar "" \(dg +.De +Returns the erase character +for the terminal, +.i i.e. , +the character used by the user to erase a single character from the input. +.Ds +.Fn flushok "WINDOW *win" "int boolf" +.De +Normally, +.Fn refresh +.Fn fflush 's +.Vn stdout +when it is finished. +.Fn flushok +allows you to control this. +if +.Vn boolf +is non-zero +(\c +.i i.e. , +non-zero) +it will do the +.Fn fflush , +otherwise it will not. +.Ds +.Fn getch "" \(dg +.De +Gets a character from the terminal and (if necessary) +echos it on the window. +\*(Es +Otherwise, the character gotten is returned. +If +.i noecho +has been set, then the window is left unaltered. +In order to retain control of the terminal, +it is necessary to have one of +.i noecho , +.i cbreak , +or +.i rawmode +set. +If you do not set one, +whatever routine you call to read characters will set +.i cbreak +for you, +and then reset to the original mode when finished. +.Ds +.Fn getstr "char *str" \(dg +.De +Get a string through the window +and put it in the location pointed to by +.Vn str , +which is assumed to be large enough to handle it. +It sets tty modes if necessary, +and then calls +.Fn getch +(or +.Fn wgetch ) +to get the characters needed to fill in the string +until a newline or EOF is encountered. +The newline stripped off the string. +\*(Es +.Ds +.Fn gettmode "" +.De +Get the tty stats. +This is normally called by +.Fn initscr . +.Ds +.Fn getyx "WINDOW *win" "int y" "int x" +.De +Puts the current \*y of +.Vn win +in the variables +.Vn y +and +.Vn x . +Since it is a macro, +not a function, +you do not pass the address +of +.Vn y +and +.Vn x . +.Ds +.Fn idlok "WINDOW *win" "int boolf" +.De +Reserved for future use. +This will eventually signal to +.Fn refresh +that it is all right to use the insert and delete line sequences +when updating the window. +.ne 1i +.Ds +.Fn inch "" \(dg +.De +Returns the character at the current position on the given window. +This does not make any changes to the window. +.Ds +.Fn initscr "" +.De +Initialize the screen routines. +This must be called before any of the screen routines are used. +It initializes the terminal-type data and such, +and without it none of the routines can operate. +If standard input is not a tty, +it sets the specifications to the terminal +whose name is pointed to by +.Vn Def\*_term +(initially "dumb"). +If the boolean +.Vn My\*_term +is non-zero, +.Vn Def\*_term +is always used. +If the system supports the +.b TIOCGWINSZ +.i ioctl(2) +call, +it is used to get the number of lines and columns for the terminal, +otherwise it is taken from the +.b termcap +description. +.Ds +.Fn insch "char c" +.De +Insert +.Vn c +at the current \*y +Each character after it shifts to the right, +and the last character disappears. +\*(Es +.Ds +.Fn insertln "" +.De +Insert a line above the current one. +Every line below the current line +will be shifted down, +and the bottom line will disappear. +The current line will become blank, +and the current \*y will remain unchanged. +.Ds +.Fn killchar "" \(dg +.De +Returns the line kill character +for the terminal, +.i i.e. , +the character used by the user to erase an entire line from the input. +.Ds +.Fn leaveok "WINDOW *win" "int boolf" \(dg +.De +Sets the boolean flag for leaving the cursor after the last change. +If +.Vn boolf +is non-zero, +the cursor will be left after the last update on the terminal, +and the current \*y for +.Vn win +will be changed accordingly. +If  +.Vn boolf + is 0 the cursor will be moved to the current \*y. +This flag +(initially 0) +retains its value until changed by the user. +.Ds +.Fn move "int y" "int x" +.De +Change the current \*y of the window to +.Vn y\*,x ). ( +\*(Es +.Ds +.Fn mvcur "int lasty" "int lastx" "int newy" "int newx" +.De +Moves the terminal's cursor from +.Vn lasty\*,lastx ) ( +to +.Vn newy\*,newx ) ( +in an approximation of optimal fashion. +This routine uses the functions borrowed from +.i ex +version 2.6. +It is possible to use this optimization +without the benefit of the screen routines. +With the screen routines, this should not be called by the user. +.Fn move +and +.Fn refresh +should be used to move the cursor position, +so that the routines know what's going on. +.Ds +.Fn mvprintw "int y" "int x" "const char *fmt" "..." +.De +Equivalent to: +.(l +move(y, x); +printw(fmt, ...); +.)l +.Ds  +.Fn mvscanw "int y" "int x" "const char *fmt" "..." +.De +Equivalent to: +.(l +move(y, x); +scanw(fmt, ...); +.)l +.Ds +.Fn mvwin "WINDOW *win" "int y" "int x" +.De +Move the home position of the window +.Vn win +from its current starting coordinates +to +.Vn y\*,x ). ( +If that would put part or all of the window +off the edge of the terminal screen, +.Fn mvwin +returns ERR and does not change anything. +For subwindows, +.Fn mvwin +also returns ERR if you attempt to move it off its main window. +If you move a main window, +all subwindows are moved along with it. +.Ds +.Fn mvwprintw "WINDOW *win" "int y" "int x" "const char *fmt" "..." +.De +Equivalent to: +.(l +wmove(win, y, x); +printw(fmt, ...); +.)l +.Ds +.Fn mvwscanw "WINDOW *win" "int y" "int x" "const char *fmt" "..." +.De +Equivalent to: +.(l +wmove(win, y, x); +scanw(fmt, ...); +.)l +.Ds +.Ft "WINDOW *" +.Fn newwin "int lines" "int cols" "int begin_y" "int begin_x"  +.De +Create a new window with +.Vn lines +lines and +.Vn cols +columns starting at position +.Vn begin\*_y\*,begin\*_x ). ( +If either +.Vn lines +or +.Vn cols +is 0 (zero), +that dimension will be set to +.Vn "LINES \- begin\*_y" ) ( +or +.Vn "COLS \- begin\*_x" ) ( +respectively. +Thus, to get a new window of dimensions +.Vn LINES +\(mu +.Vn COLS , +use +.Fn newwin 0 0 0 0 . +.Ds +.Fn nl "" \(dg +.De +Set the terminal to nl mode, +.i i.e. , +start/stop the system from mapping +.b <RETURN> +to +.b <LINE-FEED> . +If the mapping is not done, +.Fn refresh +can do more optimization, +so it is recommended, but not required, to turn it off. +.Ds +.Fn nocbreak "" \(dg +.De +Unset the terminal from cbreak mode. +.Ds +.Fn nocrmode "" \(dg +.De +Identical to +.Fn nocbreak . +The misnamed macro +.Fn nocrmode +is retained for backwards compatibility +with ealier versions of the library. +.Ds +.Fn noecho "" \(dg +.De +Turn echoing of characters off. +.Ds +.Fn nonl "" \(dg +.De +Unset the terminal to from nl mode.  See  +.Fn nl . +.ne 1i +.Ds +.Fn noraw "" \(dg +.De +Unset the terminal from raw mode.  See  +.Fn raw . +.Ds +.Fn overlay "WINDOW *win1" "WINDOW *win2" +.De +Overlay +.Vn win1 +on +.Vn win2 . +The contents of +.Vn win1 , +insofar as they fit, +are placed on +.Vn win2 +at their starting \*y. +This is done non-destructively, +i.e., blanks on +.Vn win1 +leave the contents of the space on +.Vn win2 +untouched.  Note that all non-blank characters are overwritten  +destructively in the overlay. +.Ds +.Fn overwrite "WINDOW *win1" "WINDOW *win2" +.De +Overwrite +.Vn win1 +on +.Vn win2 . +The contents of +.Vn win1 , +insofar as they fit, +are placed on +.Vn win2 +at their starting \*y. +This is done destructively, +.i i.e. , +blanks on +.Vn win1 +become blank on +.Vn win2 . +.Ds +.Fn printw "char *fmt" "..." +.De +Performs a +.Fn printf +on the window starting at the current \*y. +It uses +.Fn addstr +to add the string on the window. +It is often advisable to use the field width options of +.Fn printf +to avoid leaving things on the window from earlier calls. +\*(Es +.Ds +.Fn raw "" \(dg +.De +Set the terminal to raw mode. +On version 7 +.Un \** +.(f +\** +.Un +is a trademark of Unix System Laboratories. +.)f +this also turns off newline mapping +(see +.Fn nl ). +.Ds +.Fn refresh "" \(dg +.De +Synchronize the terminal screen with the desired window. +If the window is not a screen, +only that part covered by it is updated. +\*(Es +In this case, it will update whatever it can +without causing the scroll. +.sp +As a special case, +if +.Fn wrefresh +is called with the window +.Vn curscr +the screen is cleared +and repainted as it is currently. +This is very useful for allowing the redrawing of the screen +when the user has garbage dumped on his terminal. +.Ds +.Fn resetty "" \(dg +.De +.Fn resetty +restores them to what +.Fn savetty +stored. +These functions are performed automatically by +.Fn initscr +and +.Fn endwin .   +This function should not be used by the user. +.Ds +.Fn savetty "" \(dg +.De +.Fn savetty +saves the current tty characteristic flags. See +.Fn resetty . +This function should not be used by the user. +.Ds +.Fn scanw "char *fmt" "..." +.De +Perform a +.Fn scanf +through the window using +.Vn fmt . +It does this using consecutive calls to  +.Fn getch +(or +.Fn wgetch ). +\*(Es +.ne 1i +.Ds +.Fn scroll "WINDOW *win" +.De +Scroll the window upward one line. +This is normally not used by the user. +.Ds +.Fn scrollok "WINDOW *win" "int boolf" \(dg +.De +Set the scroll flag for the given window. +If +.Vn boolf +is 0, scrolling is not allowed. +This is its default setting. +.Ds +.Fn standend "" \(dg +.De +End standout mode initiated by +.Fn standout . +.Ds +.Fn standout "" \(dg +.De +Causes any characters added to the window +to be put in standout mode on the terminal +(if it has that capability). +.Ds +.Ft "WINDOW *" +.Fn subwin "WINDOW *win" "int lines" "int cols" "int begin_y" "int begin_x" +.De +Create a new window with +.Vn lines +lines and +.Vn cols +columns starting at position +.Vn begin\*_y\*,begin\*_x ) ( +inside the window +.i win . +This means that any change made to either window +in the area covered +by the subwindow will be made on both windows. +.Vn begin\*_y\*,begin\*_x +are specified relative to the overall screen, +not the relative (0\*,0) of +.Vn win . +If either +.Vn lines +or +.Vn cols +is 0 (zero), +that dimension will be set to +.Vn "LINES \- begin\*_y" ) ( +or +.Vn "COLS \- begin\*_x" ) ( +respectively. +.Ds +.Fn touchline "WINDOW *win" "int y" "int startx" "int endx" +.De +This function performs a function similar to +.Fn touchwin +on a single line. +It marks the first change for the given line +to be +.Vn startx , +if it is before the current first change mark, +and +the last change mark is set to be +.Vn endx +if it is currently less than +.Vn endx . +.Ds +.Fn touchoverlap "WINDOW *win1" "WINDOW *win2" +.De +Touch the window +.Vn win2 +in the area which overlaps with +.Vn win1 . +If they do not overlap, +no changes are made. +.Ds +.Fn touchwin "WINDOW *win" +.De +Make it appear that the every location on the window +has been changed. +This is usually only needed for refreshes with overlapping windows. +.Ds +.Fn tstp +.De +This function +will save the current tty state +and then put the process to sleep. +When the process gets restarted, +it restores the saved tty state +and then calls +.Fn wrefresh "curscr" +to redraw the screen. +.Fn Initscr +sets the signal +SIGTSTP +to trap to this routine. +.Ds +.Fn unctrl "char *ch" \(dg +.De +Returns a string which is an ASCII representation of +.Vn ch .   +Characters are 8 bits long. +.Ds +.Fn unctrllen "char *ch" \(dg +.De +Returns the length of the ASCII representation of  +.Vn ch . +.ne 1i +.Ds +.Fn vwprintw "WINDOW *win" "const char *fmt" "va_list ap" +.De +Identical to  +.Fn printw  +except that it takes both a window specification and a pointer to a variable +length argument list. +.Ds +.Fn vwscanw "WINDOW *win" "const char *fmt" "va_list ap" +.De +Identical to  +.Fn scanw +except that it takes both a window specification and a pointer to a variable +length argument list. +.Ds +.Fn waddbytes "WINDOW *win" "char *str" "int len" +.De +This function is the low level character output function.   +.Vn Len +characters of the string +.Vn str +are output to the current \*y position of the window specified by +.Vn win. +.sp 2 +.pp +\fIThe following functions differ from the standard functions only in their  +specification of a window, rather than the use of the default +.Vn stdscr.\fP +.Ds +.Fn waddch "WINDOW *win" "char ch"  +.Fn waddstr "WINDOW *win" "char *str"  +.Fn wclear "WINDOW *win"   +.Fn wclrtobot "WINDOW *win"   +.Fn wclrtoeol "WINDOW *win"   +.Fn wdelch "WINDOW *win"   +.Fn wdeleteln "WINDOW *win"  +.Fn werase "WINDOW *win"  +.Fn wgetch "WINDOW *win"  +.Fn wgetstr "WINDOW *win" "char *str"  +.Fn winch "WINDOW *win" \(dg +.Fn winsch "WINDOW *win" "char c"  +.Fn winsertln "WINDOW *win"  +.Fn wmove "WINDOW *win" "int y" int x"  +.Fn wprintw "WINDOW *win" "char *fmt" "..."  +.Fn wrefresh "WINDOW *win"  +.Fn wscanw "WINDOW *win" "char *fmt" "..."  +.Fn wstandend "WINDOW *win"  +.Fn wstandout "WINDOW *win" +.Dg diff --git a/lib/libcurses/addbytes.c b/lib/libcurses/addbytes.c new file mode 100644 index 000000000000..6dd8bf959b57 --- /dev/null +++ b/lib/libcurses/addbytes.c @@ -0,0 +1,157 @@ +/* + * Copyright (c) 1987, 1993, 1994 + *	The 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 sccsid[] = "@(#)addbytes.c	8.4 (Berkeley) 5/4/94"; +#endif	/* not lint */ + +#include "curses.h" + +#define	SYNCH_IN	{y = win->cury; x = win->curx;} +#define	SYNCH_OUT	{win->cury = y; win->curx = x;} + +/* + * waddbytes -- + *	Add the character to the current position in the given window. + */ +int +__waddbytes(win, bytes, count, so) +	register WINDOW *win; +	register const char *bytes; +	register int count; +	int so; +{ +	static char blanks[] = "        "; +	register int c, newx, x, y; +	char stand; +	__LINE *lp; + +	SYNCH_IN; + +#ifdef DEBUG +	__CTRACE("ADDBYTES('%c') at (%d, %d)\n", c, y, x); +#endif +	while (count--) { +		c = *bytes++; +		switch (c) { +		case '\t': +			SYNCH_OUT; +			if (waddbytes(win, blanks, 8 - (x % 8)) == ERR) +				return (ERR); +			SYNCH_IN; +			break; + +		default: +#ifdef DEBUG +	__CTRACE("ADDBYTES(%0.2o, %d, %d)\n", win, y, x); +#endif +			 +			lp = win->lines[y]; +			if (lp->flags & __ISPASTEOL) { +				lp->flags &= ~__ISPASTEOL; +newline:			if (y == win->maxy - 1) { +					if (win->flags & __SCROLLOK) { +						SYNCH_OUT; +						scroll(win); +						SYNCH_IN; +						lp = win->lines[y]; +					        x = 0; +					} else +						return (ERR); +				} else { +					y++; +					lp = win->lines[y]; +					x = 0; +				} +				if (c == '\n') +					break; +			} +				 +			stand = '\0'; +			if (win->flags & __WSTANDOUT || so) +				stand |= __STANDOUT; +#ifdef DEBUG +	__CTRACE("ADDBYTES: 1: y = %d, x = %d, firstch = %d, lastch = %d\n", +	    y, x, *win->lines[y]->firstchp, *win->lines[y]->lastchp); +#endif +			if (lp->line[x].ch != c ||  +			    !(lp->line[x].attr & stand)) { +				newx = x + win->ch_off; +				if (!(lp->flags & __ISDIRTY)) { +					lp->flags |= __ISDIRTY; +					*lp->firstchp = *lp->lastchp = newx; +				} +				else if (newx < *lp->firstchp) +					*lp->firstchp = newx; +				else if (newx > *lp->lastchp) +					*lp->lastchp = newx; +#ifdef DEBUG +	__CTRACE("ADDBYTES: change gives f/l: %d/%d [%d/%d]\n", +	    *lp->firstchp, *lp->lastchp, +	    *lp->firstchp - win->ch_off, +	    *lp->lastchp - win->ch_off); +#endif +			} +			lp->line[x].ch = c; +			if (stand) +				lp->line[x].attr |= __STANDOUT; +			else +				lp->line[x].attr &= ~__STANDOUT; +			if (x == win->maxx - 1) +				lp->flags |= __ISPASTEOL; +			else +				x++; +#ifdef DEBUG +	__CTRACE("ADDBYTES: 2: y = %d, x = %d, firstch = %d, lastch = %d\n", +	    y, x, *win->lines[y]->firstchp, *win->lines[y]->lastchp); +#endif +			break; +		case '\n': +			SYNCH_OUT; +			wclrtoeol(win); +			SYNCH_IN; +			if (!NONL) +				x = 0; +			goto newline; +		case '\r': +			x = 0; +			break; +		case '\b': +			if (--x < 0) +				x = 0; +			break; +		} +	} +	SYNCH_OUT; +	return (OK); +} diff --git a/lib/libcurses/addch.c b/lib/libcurses/addch.c new file mode 100644 index 000000000000..d5f30014c02f --- /dev/null +++ b/lib/libcurses/addch.c @@ -0,0 +1,66 @@ +/* + * Copyright (c) 1981, 1993, 1994 + *	The 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 sccsid[] = "@(#)addch.c	8.2 (Berkeley) 5/4/94"; +#endif	/* not lint */ + +#include "curses.h" + +/* + * waddch -- + *	Add the character to the current position in the given window. + * + */ +int +waddch(win, ch) +	WINDOW *win; +	int ch; +{ +	__LDATA buf; + +	buf.ch = ch; +	buf.attr = 0; +	return (__waddch(win, &buf)); +} + +int +__waddch(win, dp) +	WINDOW *win; +	__LDATA *dp; +{ +	char buf[2]; + +	buf[0] = dp->ch; +	return (__waddbytes(win, buf, 1, dp->attr & __STANDOUT)); +} diff --git a/lib/libcurses/addnstr.c b/lib/libcurses/addnstr.c new file mode 100644 index 000000000000..92a6e681a54f --- /dev/null +++ b/lib/libcurses/addnstr.c @@ -0,0 +1,62 @@ +/* + * Copyright (c) 1993, 1994 + *	The 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 sccsid[] = "@(#)addnstr.c	8.2 (Berkeley) 5/4/94"; +#endif	/* not lint */ + +#include <string.h> + +#include "curses.h" + +/* + * waddnstr -- + *	Add a string (at most n characters) to the given window + *	starting at (_cury, _curx).  If n is negative, add the + *	entire string. + */ +int +waddnstr(win, s, n) +	WINDOW *win; +	const char *s; +	int n; +{ +	size_t len; +	const char *p; + +	if (n > 0) +		for (p = s, len = 0; n-- && *p++; ++len); +	else +		len = strlen(s); +	return (waddbytes(win, s, len)); +} diff --git a/lib/libcurses/box.c b/lib/libcurses/box.c new file mode 100644 index 000000000000..191e37cfd82f --- /dev/null +++ b/lib/libcurses/box.c @@ -0,0 +1,78 @@ +/* + * Copyright (c) 1981, 1993, 1994 + *	The 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 sccsid[] = "@(#)box.c	8.2 (Berkeley) 5/4/94"; +#endif	/* not lint */ + +#include "curses.h" + +/* + * box -- + *	Draw a box around the given window with "vert" as the vertical + *	delimiting char, and "hor", as the horizontal one. + */ +int +box(win, vert, hor) +	register WINDOW *win; +	int vert, hor; +{ +	register int endy, endx, i; +	register __LDATA *fp, *lp; + +	endx = win->maxx; +	endy = win->maxy - 1; +	fp = win->lines[0]->line; +	lp = win->lines[endy]->line; +	for (i = 0; i < endx; i++) { +		fp[i].ch = lp[i].ch = hor; +		fp[i].attr &= ~__STANDOUT; +		lp[i].attr &= ~__STANDOUT; +	} +	endx--; +	for (i = 0; i <= endy; i++) { +		win->lines[i]->line[0].ch = vert; +	        win->lines[i]->line[endx].ch = vert; +		win->lines[i]->line[0].attr &= ~__STANDOUT; +		win->lines[i]->line[endx].attr &= ~__STANDOUT; +	} +	if (!(win->flags & __SCROLLOK) && (win->flags & __SCROLLWIN)) { +		fp[0].ch = fp[endx].ch = lp[0].ch = lp[endx].ch = ' '; +		fp[0].attr &= ~__STANDOUT; +		fp[endx].attr &= ~__STANDOUT; +		lp[0].attr &= ~__STANDOUT; +		lp[endx].attr &= ~__STANDOUT; +	} +	__touchwin(win); +	return (OK); +} diff --git a/lib/libcurses/clear.c b/lib/libcurses/clear.c new file mode 100644 index 000000000000..54c0b30d3cfc --- /dev/null +++ b/lib/libcurses/clear.c @@ -0,0 +1,53 @@ +/* + * Copyright (c) 1981, 1993, 1994 + *	The 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 sccsid[] = "@(#)clear.c	8.2 (Berkeley) 5/4/94"; +#endif	/* not lint */ + +#include "curses.h" + +/* + * wclear -- + *	Clear the window. + */ +int +wclear(win) +	register WINDOW *win; +{ +	if (werase(win) == OK) { +		win->flags |= __CLEAROK; +		return (OK); +	} +	return (ERR); +} diff --git a/lib/libcurses/clrtobot.c b/lib/libcurses/clrtobot.c new file mode 100644 index 000000000000..81ee6a4603ad --- /dev/null +++ b/lib/libcurses/clrtobot.c @@ -0,0 +1,75 @@ +/* + * Copyright (c) 1981, 1993, 1994 + *	The 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 sccsid[] = "@(#)clrtobot.c	8.2 (Berkeley) 5/4/94"; +#endif	/* not lint */ + +#include "curses.h" + +/* + * wclrtobot -- + *	Erase everything on the window. + */ +int +wclrtobot(win) +	register WINDOW *win; +{ +	register int minx, startx, starty, y; +	register __LDATA *sp, *end, *maxx; + +	if (win->lines[win->cury]->flags & __ISPASTEOL) { +		starty = win->cury + 1; +		startx = 0; +	} else { +		starty = win->cury; +		startx = win->curx; +	} +	for (y = starty; y < win->maxy; y++) { +		minx = -1; +		end = &win->lines[y]->line[win->maxx]; +		for (sp = &win->lines[y]->line[startx]; sp < end; sp++) +			if (sp->ch != ' ' || sp->attr != 0) { +				maxx = sp; +				if (minx == -1) +					minx = sp - win->lines[y]->line; +				sp->ch = ' '; +				sp->attr = 0; +			} +		if (minx != -1) +			__touchline(win, y, minx, maxx - win->lines[y]->line, +		            0); +		startx = 0; +	} +	return (OK); +} diff --git a/lib/libcurses/clrtoeol.c b/lib/libcurses/clrtoeol.c new file mode 100644 index 000000000000..44fc190fee3d --- /dev/null +++ b/lib/libcurses/clrtoeol.c @@ -0,0 +1,83 @@ +/* + * Copyright (c) 1981, 1993, 1994 + *	The 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 sccsid[] = "@(#)clrtoeol.c	8.2 (Berkeley) 5/4/94"; +#endif	/* not lint */ + +#include "curses.h" + +/* + * wclrtoeol -- + *	Clear up to the end of line. + */ +int +wclrtoeol(win) +	register WINDOW *win; +{ +	register int minx, x, y; +	register __LDATA *end, *maxx, *sp; + +	y = win->cury; +	x = win->curx; +	if (win->lines[y]->flags & __ISPASTEOL) { +		if (y < win->maxy - 1) { +			y++; +			x = 0; +		} else +			return (OK); +	} +	end = &win->lines[y]->line[win->maxx]; +	minx = -1; +	maxx = &win->lines[y]->line[x]; +	for (sp = maxx; sp < end; sp++) +		if (sp->ch != ' ' || sp->attr != 0) { +			maxx = sp; +			if (minx == -1) +				minx = sp - win->lines[y]->line; +			sp->ch = ' '; +			sp->attr = 0; +		} +#ifdef DEBUG +	__CTRACE("CLRTOEOL: minx = %d, maxx = %d, firstch = %d, lastch = %d\n", +	    minx, maxx - win->lines[y]->line, *win->lines[y]->firstchp,  +	    *win->lines[y]->lastchp); +#endif +	/* Update firstch and lastch for the line. */ +	return (__touchline(win, y, x, win->maxx - 1, 0)); +} + + + + + diff --git a/lib/libcurses/cr_put.c b/lib/libcurses/cr_put.c new file mode 100644 index 000000000000..ada2df5ca1e5 --- /dev/null +++ b/lib/libcurses/cr_put.c @@ -0,0 +1,432 @@ +/* + * Copyright (c) 1981, 1993, 1994 + *	The 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 sccsid[] = "@(#)cr_put.c	8.3 (Berkeley) 5/4/94"; +#endif	/* not lint */ + +#include <string.h> + +#include "curses.h" + +#define	HARDTABS	8 + +/* + * Terminal driving and line formatting routines.  Basic motion optimizations + * are done here as well as formatting lines (printing of control characters, + * line numbering and the like). + */ + +/* Stub function for the users. */ +int +mvcur(ly, lx, y, x) +	int ly, lx, y, x; +{ +	return (__mvcur(ly, lx, y, x, 0)); +} + +static void	fgoto __P((int)); +static int	plod __P((int, int)); +static void	plodput __P((int)); +static int	tabcol __P((int, int)); + +static int outcol, outline, destcol, destline; + +/* + * Sync the position of the output cursor.  Most work here is rounding for + * terminal boundaries getting the column position implied by wraparound or + * the lack thereof and rolling up the screen to get destline on the screen. + */ +int +__mvcur(ly, lx, y, x, in_refresh) +	int ly, lx, y, x, in_refresh; +{ +#ifdef DEBUG +	__CTRACE("mvcur: moving cursor from (%d, %d) to (%d, %d)\n", +	    ly, lx, y, x); +#endif +	destcol = x; +	destline = y; +	outcol = lx; +	outline = ly; +	fgoto(in_refresh); +	return (OK); +}	 +         +static void +fgoto(in_refresh) +	int in_refresh; +{ +	register int c, l; +	register char *cgp; + +	if (destcol >= COLS) { +		destline += destcol / COLS; +		destcol %= COLS; +	} +	if (outcol >= COLS) { +		l = (outcol + 1) / COLS; +		outline += l; +		outcol %= COLS; +		if (AM == 0) { +			while (l > 0) { +				if (__pfast) +					if (CR) +						tputs(CR, 0, __cputchar); +					else +						putchar('\r'); +				if (NL) +					tputs(NL, 0, __cputchar); +				else +					putchar('\n'); +				l--; +			} +			outcol = 0; +		} +		if (outline > LINES - 1) { +			destline -= outline - (LINES - 1); +			outline = LINES - 1; +		} +	} +	if (destline >= LINES) { +		l = destline; +		destline = LINES - 1; +		if (outline < LINES - 1) { +			c = destcol; +			if (__pfast == 0 && !CA) +				destcol = 0; +			fgoto(in_refresh); +			destcol = c; +		} +		while (l >= LINES) { +			/* The following linefeed (or simulation thereof) is +			 * supposed to scroll up the screen, since we are on +			 * the bottom line.  We make the assumption that +			 * linefeed will scroll.  If ns is in the capability +			 * list this won't work.  We should probably have an +			 * sc capability but sf will generally take the place +			 * if it works. +			 *  +			 * Superbee glitch: in the middle of the screen have +			 * to use esc B (down) because linefeed screws up in +			 * "Efficient Paging" (what a joke) mode (which is +			 * essential in some SB's because CRLF mode puts +			 * garbage in at end of memory), but you must use +			 * linefeed to scroll since down arrow won't go past +			 * memory end. I turned this off after recieving Paul +			 * Eggert's Superbee description which wins better. +			 */ +			if (NL /* && !XB */ && __pfast) +				tputs(NL, 0, __cputchar); +			else +				putchar('\n'); +			l--; +			if (__pfast == 0) +				outcol = 0; +		} +	} +	if (destline < outline && !(CA || UP)) +		destline = outline; +	if (CA) { +		cgp = tgoto(CM, destcol, destline); + +		/* +		 * Need this condition due to inconsistent behavior +		 * of backspace on the last column. +		 */ +		if (outcol != COLS - 1 && plod(strlen(cgp), in_refresh) > 0) +			plod(0, in_refresh); +		else  +			tputs(cgp, 0, __cputchar); +	} else +		plod(0, in_refresh); +	outline = destline; +	outcol = destcol; +} +/* + * Move (slowly) to destination. + * Hard thing here is using home cursor on really deficient terminals. + * Otherwise just use cursor motions, hacking use of tabs and overtabbing + * and backspace. + */ + +static int plodcnt, plodflg; + +static void +plodput(c) +	int c; +{ +	if (plodflg) +		--plodcnt; +	else +		putchar(c); +} + +static int +plod(cnt, in_refresh) +	int cnt, in_refresh; +{ +	register int i, j, k, soutcol, soutline; + +	plodcnt = plodflg = cnt; +	soutcol = outcol; +	soutline = outline; +	/* +	 * Consider homing and moving down/right from there, vs. moving +	 * directly with local motions to the right spot. +	 */ +	if (HO) { +		/* +		 * i is the cost to home and tab/space to the right to get to +		 * the proper column.  This assumes ND space costs 1 char.  So +		 * i + destcol is cost of motion with home. +		 */ +		if (GT) +			i = (destcol / HARDTABS) + (destcol % HARDTABS); +		else +			i = destcol; + +		/* j is cost to move locally without homing. */ +		if (destcol >= outcol) {	/* if motion is to the right */ +			j = destcol / HARDTABS - outcol / HARDTABS; +			if (GT && j) +				j += destcol % HARDTABS; +			else +				j = destcol - outcol; +		} else +			/* leftward motion only works if we can backspace. */ +			if (outcol - destcol <= i && (BS || BC)) +				/* Cheaper to backspace. */ +				i = j = outcol - destcol; +			else +				/* Impossibly expensive. */ +				j = i + 1; + +		/* k is the absolute value of vertical distance. */ +		k = outline - destline; +		if (k < 0) +			k = -k; +		j += k; + +		/* Decision.  We may not have a choice if no UP. */ +		if (i + destline < j || (!UP && destline < outline)) { +			/* +			 * Cheaper to home.  Do it now and pretend it's a +			 * regular local motion. +			 */ +			tputs(HO, 0, plodput); +			outcol = outline = 0; +		} else if (LL) { +			/* +			 * Quickly consider homing down and moving from there. +			 * Assume cost of LL is 2. +			 */ +			k = (LINES - 1) - destline; +			if (i + k + 2 < j && (k <= 0 || UP)) { +				tputs(LL, 0, plodput); +				outcol = 0; +				outline = LINES - 1; +			} +		} +	} else +		/* No home and no up means it's impossible. */ +		if (!UP && destline < outline) +			return (-1); +	if (GT) +		i = destcol % HARDTABS + destcol / HARDTABS; +	else +		i = destcol; +#ifdef notdef +	if (BT && outcol > destcol && +	    (j = (((outcol+7) & ~7) - destcol - 1) >> 3)) { +		j *= (k = strlen(BT)); +		if ((k += (destcol&7)) > 4) +			j += 8 - (destcol&7); +		else +			j += k; +	} +	else +#endif +		j = outcol - destcol; + +	/* +	 * If we will later need a \n which will turn into a \r\n by the +	 * system or the terminal, then don't bother to try to \r. +	 */ +	if ((NONL || !__pfast) && outline < destline) +		goto dontcr; + +	/* +	 * If the terminal will do a \r\n and there isn't room for it, then +	 * we can't afford a \r. +	 */ +	if (NC && outline >= destline) +		goto dontcr; + +	/* +	 * If it will be cheaper, or if we can't back up, then send a return +	 * preliminarily. +	 */ +	if (j > i + 1 || outcol > destcol && !BS && !BC) { +		/* +		 * BUG: this doesn't take the (possibly long) length of CR +		 * into account. +		 */ +		if (CR) +			tputs(CR, 0, plodput); +		else +			plodput('\r'); +		if (NC) { +			if (NL) +				tputs(NL, 0, plodput); +			else +				plodput('\n'); +			outline++; +		} +		outcol = 0; +	} + +dontcr:	while (outline < destline) { +		outline++; +		if (NL) +			tputs(NL, 0, plodput); +		else +			plodput('\n'); +		if (plodcnt < 0) +			goto out; +		if (NONL || __pfast == 0) +			outcol = 0; +	} +	if (BT) +		k = strlen(BT); +	while (outcol > destcol) { +		if (plodcnt < 0) +			goto out; +#ifdef notdef +		if (BT && outcol - destcol > k + 4) { +			tputs(BT, 0, plodput); +			outcol--; +			outcol &= ~7; +			continue; +		} +#endif +		outcol--; +		if (BC) +			tputs(BC, 0, plodput); +		else +			plodput('\b'); +	} +	while (outline > destline) { +		outline--; +		tputs(UP, 0, plodput); +		if (plodcnt < 0) +			goto out; +	} +	if (GT && destcol - outcol > 1) { +		for (;;) { +			i = tabcol(outcol, HARDTABS); +			if (i > destcol) +				break; +			if (TA) +				tputs(TA, 0, plodput); +			else +				plodput('\t'); +			outcol = i; +		} +		if (destcol - outcol > 4 && i < COLS && (BC || BS)) { +			if (TA) +				tputs(TA, 0, plodput); +			else +				plodput('\t'); +			outcol = i; +			while (outcol > destcol) { +				outcol--; +				if (BC) +					tputs(BC, 0, plodput); +				else +					plodput('\b'); +			} +		} +	} +	while (outcol < destcol) { +		/* +		 * Move one char to the right.  We don't use ND space because +		 * it's better to just print the char we are moving over. +		 */ +		if (in_refresh) +			if (plodflg)	/* Avoid a complex calculation. */ +				plodcnt--; +			else { +				i = curscr->lines[outline]->line[outcol].ch; +				if ((curscr->lines[outline]->line[outcol].attr +				     & __STANDOUT) == +				    (curscr->flags & __WSTANDOUT)) +					putchar(i); +				else +					goto nondes; +			} +		else +nondes:			if (ND) +				tputs(ND, 0, plodput); +			else +				plodput(' '); +		outcol++; +		if (plodcnt < 0) +			goto out; +	} + +out:	if (plodflg) { +		outcol = soutcol; +		outline = soutline; +	} +	return (plodcnt); +} + +/* + * Return the column number that results from being in column col and + * hitting a tab, where tabs are set every ts columns.  Work right for + * the case where col > COLS, even if ts does not divide COLS. + */ +static int +tabcol(col, ts) +	int col, ts; +{ +	int offset; + +	if (col >= COLS) { +		offset = COLS * (col / COLS); +		col -= offset; +	} else +		offset = 0; +	return (col + ts - (col % ts) + offset); +} diff --git a/lib/libcurses/curses.c b/lib/libcurses/curses.c new file mode 100644 index 000000000000..07cbb5b4afd8 --- /dev/null +++ b/lib/libcurses/curses.c @@ -0,0 +1,74 @@ +/* + * Copyright (c) 1981, 1993, 1994 + *	The 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 sccsid[] = "@(#)curses.c	8.3 (Berkeley) 5/4/94"; +#endif /* not lint */ + +#include "curses.h" + +/* Private. */ +int	__echoit = 1;			/* If stty indicates ECHO. */ +int	__pfast; +int	__rawmode = 0;			/* If stty indicates RAW mode. */ +int	__noqch = 0;			/*  +					 * If terminal doesn't have  +					 * insert/delete line capabilities  +					 * for quick change on refresh. +					 */ +char	AM, BS, CA, DA, EO, HC, IN, MI, MS, NC, NS, OS, PC, +	UL, XB, XN, XT, XS, XX; +char	*AL, *BC, *BT, *CD, *CE, *CL, *CM, *CR, *CS, *DC, *DL, +	*DM, *DO, *ED, *EI, *K0, *K1, *K2, *K3, *K4, *K5, *K6, +	*K7, *K8, *K9, *HO, *IC, *IM, *IP, *KD, *KE, *KH, *KL, +	*KR, *KS, *KU, *LL, *MA, *ND, *NL, *RC, *SC, *SE, *SF, +	*SO, *SR, *TA, *TE, *TI, *UC, *UE, *UP, *US, *VB, *VS, +	*VE, *al, *dl, *sf, *sr, +	*AL_PARM, *DL_PARM, *UP_PARM, *DOWN_PARM, *LEFT_PARM, +	*RIGHT_PARM; +/* + * Public. + * + * XXX + * UPPERCASE isn't used by libcurses, and is left for backward + * compatibility only. + */ +WINDOW	*curscr;			/* Current screen. */ +WINDOW	*stdscr;			/* Standard screen. */ +int	 COLS;				/* Columns on the screen. */ +int	 LINES;				/* Lines on the screen. */ +int	 My_term = 0;			/* Use Def_term regardless. */ +char	*Def_term = "unknown";		/* Default terminal type. */ +char	 GT;				/* Gtty indicates tabs. */ +char	 NONL;				/* Term can't hack LF doing a CR. */ +char	 UPPERCASE;			/* Terminal is uppercase only. */ diff --git a/lib/libcurses/curses.h b/lib/libcurses/curses.h new file mode 100644 index 000000000000..d6f9d65c145b --- /dev/null +++ b/lib/libcurses/curses.h @@ -0,0 +1,336 @@ +/* + * Copyright (c) 1981, 1993, 1994 + *	The 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. + * + *	@(#)curses.h	8.5 (Berkeley) 4/29/95 + */ + +#ifndef _CURSES_H_ +#define	_CURSES_H_ + +#include <stdio.h> + +/* + * The following #defines and #includes are present for backward + * compatibility only.  They should not be used in future code. + * + * START BACKWARD COMPATIBILITY ONLY. + */ +#ifndef _CURSES_PRIVATE +#ifndef __cplusplus +#define	bool	char +#endif +#define	reg	register + +#ifndef TRUE +#define	TRUE	(1) +#endif +#ifndef FALSE +#define	FALSE	(0) +#endif + +#define	_puts(s)	tputs(s, 0, __cputchar) +#define	_putchar(c)	__cputchar(c) + +/* Old-style terminal modes access. */ +#define	baudrate()	(cfgetospeed(&__baset)) +#define	crmode()	cbreak() +#define	erasechar()	(__baset.c_cc[VERASE]) +#define	killchar()	(__baset.c_cc[VKILL]) +#define	nocrmode()	nocbreak() +#define	ospeed		(cfgetospeed(&__baset)) +#endif /* _CURSES_PRIVATE */ + +extern char	 GT;			/* Gtty indicates tabs. */ +extern char	 NONL;			/* Term can't hack LF doing a CR. */ +extern char	 UPPERCASE;		/* Terminal is uppercase only. */ + +extern int	 My_term;		/* Use Def_term regardless. */ +extern char	*Def_term;		/* Default terminal type. */ + +/* Termcap capabilities. */ +extern char	AM, BS, CA, DA, EO, HC, IN, MI, MS, NC, NS, OS, +		PC, UL, XB, XN, XT, XS, XX; +extern char	*AL, *BC, *BT, *CD, *CE, *CL, *CM, *CR, *CS, *DC, *DL, +		*DM, *DO, *ED, *EI, *K0, *K1, *K2, *K3, *K4, *K5, *K6, +		*K7, *K8, *K9, *HO, *IC, *IM, *IP, *KD, *KE, *KH, *KL, +		*KR, *KS, *KU, *LL, *MA, *ND, *NL, *RC, *SC, *SE, *SF, +		*SO, *SR, *TA, *TE, *TI, *UC, *UE, *UP, *US, *VB, *VS, +		*VE, *al, *dl, *sf, *sr, +		*AL_PARM, *DL_PARM, *UP_PARM, *DOWN_PARM, *LEFT_PARM, +		*RIGHT_PARM; + +/* END BACKWARD COMPATIBILITY ONLY. */ + +/* 8-bit ASCII characters. */ +#define	unctrl(c)		__unctrl[(c) & 0xff] +#define	unctrllen(ch)		__unctrllen[(ch) & 0xff] + +extern char	*__unctrl[256];	/* Control strings. */ +extern char	 __unctrllen[256];	/* Control strings length. */ + +/* + * A window an array of __LINE structures pointed to by the 'lines' pointer. + * A line is an array of __LDATA structures pointed to by the 'line' pointer. + * + * IMPORTANT: the __LDATA structure must NOT induce any padding, so if new + * fields are added -- padding fields with *constant values* should ensure  + * that the compiler will not generate any padding when storing an array of + *  __LDATA structures.  This is to enable consistent use of memcmp, and memcpy + * for comparing and copying arrays. + */ +typedef struct { +	char ch;			/* the actual character */ + +#define	__STANDOUT	0x01  		/* Added characters are standout. */ +	char attr;			/* attributes of character */ +} __LDATA; + +#define __LDATASIZE	(sizeof(__LDATA)) + +typedef struct { +#define	__ISDIRTY	0x01		/* Line is dirty. */ +#define __ISPASTEOL	0x02		/* Cursor is past end of line */ +#define __FORCEPAINT	0x04		/* Force a repaint of the line */ +	u_int flags; +	u_int hash;			/* Hash value for the line. */ +	size_t *firstchp, *lastchp;	/* First and last chngd columns ptrs */ +	size_t firstch, lastch;		/* First and last changed columns. */ +	__LDATA *line;			/* Pointer to the line text. */ +} __LINE; + +typedef struct __window {		/* Window structure. */ +	struct __window	*nextp, *orig;	/* Subwindows list and parent. */ +	size_t begy, begx;		/* Window home. */ +	size_t cury, curx;		/* Current x, y coordinates. */ +	size_t maxy, maxx;		/* Maximum values for curx, cury. */ +	short ch_off;			/* x offset for firstch/lastch. */ +	__LINE **lines;			/* Array of pointers to the lines */ +	__LINE  *lspace;		/* line space (for cleanup) */ +	__LDATA *wspace;		/* window space (for cleanup) */ + +#define	__ENDLINE	0x001		/* End of screen. */ +#define	__FLUSH		0x002		/* Fflush(stdout) after refresh. */ +#define	__FULLWIN	0x004		/* Window is a screen. */ +#define	__IDLINE	0x008		/* Insert/delete sequences. */ +#define	__SCROLLWIN	0x010		/* Last char will scroll window. */ +#define	__SCROLLOK	0x020		/* Scrolling ok. */ +#define	__CLEAROK	0x040		/* Clear on next refresh. */ +#define __WSTANDOUT	0x080		/* Standout window */ +#define __LEAVEOK	0x100		/* If curser left */	 +	u_int flags; +} WINDOW; + +/* Curses external declarations. */ +extern WINDOW	*curscr;		/* Current screen. */ +extern WINDOW	*stdscr;		/* Standard screen. */ + +extern struct termios __orig_termios;	/* Terminal state before curses */ +extern struct termios __baset;		/* Our base terminal state */ +extern int __tcaction;			/* If terminal hardware set. */ + +extern int	 COLS;			/* Columns on the screen. */ +extern int	 LINES;			/* Lines on the screen. */ + +extern char	*ttytype;		/* Full name of current terminal. */ + +#define	ERR	(0)			/* Error return. */ +#define	OK	(1)			/* Success return. */ + +/* Standard screen pseudo functions. */ +#define	addbytes(s, n)			__waddbytes(stdscr, s, n, 0) +#define	addch(ch)			waddch(stdscr, ch) +#define	addnstr(s, n)			waddnstr(stdscr, s, n) +#define	addstr(s)			__waddbytes(stdscr, s, strlen(s), 0) +#define	clear()				wclear(stdscr) +#define	clrtobot()			wclrtobot(stdscr) +#define	clrtoeol()			wclrtoeol(stdscr) +#define	delch()				wdelch(stdscr) +#define	deleteln()			wdeleteln(stdscr) +#define	erase()				werase(stdscr) +#define	getch()				wgetch(stdscr) +#define	getstr(s)			wgetstr(stdscr, s) +#define	inch()				winch(stdscr) +#define	insch(ch)			winsch(stdscr, ch) +#define	insertln()			winsertln(stdscr) +#define	move(y, x)			wmove(stdscr, y, x) +#define	refresh()			wrefresh(stdscr) +#define	standend()			wstandend(stdscr) +#define	standout()			wstandout(stdscr) +#define	waddbytes(w, s, n)		__waddbytes(w, s, n, 0) +#define	waddstr(w, s)			__waddbytes(w, s, strlen(s), 0) + +/* Standard screen plus movement pseudo functions. */ +#define	mvaddbytes(y, x, s, n)		mvwaddbytes(stdscr, y, x, s, n) +#define	mvaddch(y, x, ch)		mvwaddch(stdscr, y, x, ch) +#define	mvaddnstr(y, x, s, n)		mvwaddnstr(stdscr, y, x, s, n) +#define	mvaddstr(y, x, s)		mvwaddstr(stdscr, y, x, s) +#define	mvdelch(y, x)			mvwdelch(stdscr, y, x) +#define	mvgetch(y, x)			mvwgetch(stdscr, y, x) +#define	mvgetstr(y, x, s)		mvwgetstr(stdscr, y, x, s) +#define	mvinch(y, x)			mvwinch(stdscr, y, x) +#define	mvinsch(y, x, c)		mvwinsch(stdscr, y, x, c) +#define	mvwaddbytes(w, y, x, s, n) \ +	(wmove(w, y, x) == ERR ? ERR : __waddbytes(w, s, n, 0)) +#define	mvwaddch(w, y, x, ch) \ +	(wmove(w, y, x) == ERR ? ERR : waddch(w, ch)) +#define	mvwaddnstr(w, y, x, s, n) \ +	(wmove(w, y, x) == ERR ? ERR : waddnstr(w, s, n)) +#define	mvwaddstr(w, y, x, s) \ +	(wmove(w, y, x) == ERR ? ERR : __waddbytes(w, s, strlen(s), 0)) +#define	mvwdelch(w, y, x) \ +	(wmove(w, y, x) == ERR ? ERR : wdelch(w)) +#define	mvwgetch(w, y, x) \ +	(wmove(w, y, x) == ERR ? ERR : wgetch(w)) +#define	mvwgetstr(w, y, x, s) \ +	(wmove(w, y, x) == ERR ? ERR : wgetstr(w, s)) +#define	mvwinch(w, y, x) \ +	(wmove(w, y, x) == ERR ? ERR : winch(w)) +#define	mvwinsch(w, y, x, c) \ +	(wmove(w, y, x) == ERR ? ERR : winsch(w, c)) + +/* Psuedo functions. */ +#define	clearok(w, bf) \ +	((bf) ? ((w)->flags |= __CLEAROK) : ((w)->flags &= ~__CLEAROK)) +#define	flushok(w, bf) \ +	((bf) ? ((w)->flags |= __FLUSH) : ((w)->flags &= ~__FLUSH)) +#define	getyx(w, y, x) \ +	(y) = (w)->cury, (x) = (w)->curx +#define	leaveok(w, bf) \ +	((bf) ? ((w)->flags |= __LEAVEOK) : ((w)->flags &= ~__LEAVEOK)) +#define	scrollok(w, bf) \ +	((bf) ? ((w)->flags |= __SCROLLOK) : ((w)->flags &= ~__SCROLLOK)) +#define	winch(w) \ +	((w)->lines[(w)->cury]->line[(w)->curx].ch & 0177) + +/* Public function prototypes. */ +int	 box __P((WINDOW *, int, int)); +int	 cbreak __P((void)); +int	 delwin __P((WINDOW *)); +int	 echo __P((void)); +int	 endwin __P((void)); +char	*fullname __P((char *, char *)); +char	*getcap __P((char *)); +int	 gettmode __P((void)); +void	 idlok __P((WINDOW *, int)); +WINDOW	*initscr __P((void)); +char	*longname __P((char *, char *)); +int	 mvcur __P((int, int, int, int)); +int	 mvprintw __P((int, int, const char *, ...)); +int	 mvscanw __P((int, int, const char *, ...)); +int	 mvwin __P((WINDOW *, int, int)); +int	 mvwprintw __P((WINDOW *, int, int, const char *, ...)); +int	 mvwscanw __P((WINDOW *, int, int, const char *, ...)); +WINDOW	*newwin __P((int, int, int, int)); +int	 nl __P((void)); +int	 nocbreak __P((void)); +int	 noecho __P((void)); +int	 nonl __P((void)); +int	 noraw __P((void)); +int	 overlay __P((WINDOW *, WINDOW *)); +int	 overwrite __P((WINDOW *, WINDOW *)); +int	 printw __P((const char *, ...)); +int	 raw __P((void)); +int	 resetty __P((void)); +int	 savetty __P((void)); +int	 scanw __P((const char *, ...)); +int	 scroll __P((WINDOW *)); +int	 setterm __P((char *)); +int	 sscans __P((WINDOW *, const char *, ...)); +WINDOW	*subwin __P((WINDOW *, int, int, int, int)); +int	 suspendwin __P((void)); +int	 touchline __P((WINDOW *, int, int, int)); +int	 touchoverlap __P((WINDOW *, WINDOW *)); +int	 touchwin __P((WINDOW *)); +int 	 vwprintw __P((WINDOW *, const char *, _BSD_VA_LIST_)); +int      vwscanw __P((WINDOW *, const char *, _BSD_VA_LIST_)); +int	 waddch __P((WINDOW *, int)); +int	 waddnstr __P((WINDOW *, const char *, int)); +int	 wclear __P((WINDOW *)); +int	 wclrtobot __P((WINDOW *)); +int	 wclrtoeol __P((WINDOW *)); +int	 wdelch __P((WINDOW *)); +int	 wdeleteln __P((WINDOW *)); +int	 werase __P((WINDOW *)); +int	 wgetch __P((WINDOW *)); +int	 wgetstr __P((WINDOW *, char *)); +int	 winsch __P((WINDOW *, int)); +int	 winsertln __P((WINDOW *)); +int	 wmove __P((WINDOW *, int, int)); +int	 wprintw __P((WINDOW *, const char *, ...)); +int	 wrefresh __P((WINDOW *)); +int	 wscanw __P((WINDOW *, const char *, ...)); +int	 wstandend __P((WINDOW *)); +int	 wstandout __P((WINDOW *)); +int	 vwprintw __P((WINDOW *, const char *, _BSD_VA_LIST_)); + +/* Private functions that are needed for user programs prototypes. */ +void	 __cputchar __P((int)); +int	 __waddbytes __P((WINDOW *, const char *, int, int)); + +/* Private functions. */ +#ifdef _CURSES_PRIVATE +void	 __CTRACE __P((const char *, ...)); +u_int	 __hash __P((char *, int)); +void	 __id_subwins __P((WINDOW *)); +int	 __mvcur __P((int, int, int, int, int)); +void	 __restore_stophandler __P((void)); +void	 __set_stophandler __P((void)); +void	 __set_subwin __P((WINDOW *, WINDOW *)); +void	 __startwin __P((void)); +void	 __stop_signal_handler __P((int)); +void	 __swflags __P((WINDOW *)); +int	 __touchline __P((WINDOW *, int, int, int, int)); +int	 __touchwin __P((WINDOW *)); +char	*__tscroll __P((const char *, int, int)); +int	 __waddch __P((WINDOW *, __LDATA *)); + +/* Private #defines. */ +#define	min(a,b)	(a < b ? a : b) +#define	max(a,b)	(a > b ? a : b) + +/* Private externs. */ +extern int	 __echoit; +extern int	 __endwin; +extern int	 __pfast; +extern int	 __rawmode; +extern int	 __noqch; +#endif + +/* Termcap functions. */ +int	 tgetent __P((char *, char *)); +int	 tgetnum __P((char *)); +int	 tgetflag __P((char *)); +char	*tgetstr __P((char *, char **)); +char	*tgoto __P((char *, int, int)); +int	 tputs __P((char *, int, void (*)(int))); + +#endif /* !_CURSES_H_ */ diff --git a/lib/libcurses/delch.c b/lib/libcurses/delch.c new file mode 100644 index 000000000000..b9cdc3140ed3 --- /dev/null +++ b/lib/libcurses/delch.c @@ -0,0 +1,63 @@ +/* + * Copyright (c) 1981, 1993, 1994 + *	The 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 sccsid[] = "@(#)delch.c	8.2 (Berkeley) 5/4/94"; +#endif	/* not lint */ + +#include <string.h> + +#include "curses.h" + +/* + * wdelch -- + *	Do an insert-char on the line, leaving (cury, curx) unchanged. + */ +int +wdelch(win) +	register WINDOW *win; +{ +	register __LDATA *end, *temp1, *temp2; + +	end = &win->lines[win->cury]->line[win->maxx - 1]; +	temp1 = &win->lines[win->cury]->line[win->curx]; +	temp2 = temp1 + 1; +	while (temp1 < end) { +		(void)memcpy(temp1, temp2, sizeof(__LDATA)); +		temp1++, temp2++; +	} +	temp1->ch = ' '; +	temp1->attr = 0; +	__touchline(win, win->cury, win->curx, win->maxx - 1, 0); +	return (OK); +} diff --git a/lib/libcurses/deleteln.c b/lib/libcurses/deleteln.c new file mode 100644 index 000000000000..4cb08ea37947 --- /dev/null +++ b/lib/libcurses/deleteln.c @@ -0,0 +1,82 @@ +/* + * Copyright (c) 1981, 1993, 1994 + *	The 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 sccsid[] = "@(#)deleteln.c	8.2 (Berkeley) 5/4/94"; +#endif	/* not lint */ + +#include <string.h> + +#include "curses.h" + +/* + * wdeleteln -- + *	Delete a line from the screen.  It leaves (cury, curx) unchanged. + */ +int +wdeleteln(win) +	register WINDOW *win; +{ +	register int y, i; +	register __LINE *temp; + +#ifdef DEBUG +	__CTRACE("deleteln: (%0.2o)\n", win); +#endif +	temp = win->lines[win->cury]; +	for (y = win->cury; y < win->maxy - 1; y++) { +		win->lines[y]->flags &= ~__ISPASTEOL; +		win->lines[y + 1]->flags &= ~__ISPASTEOL; +		if (win->orig == NULL) +			win->lines[y] = win->lines[y + 1]; +		else +			(void) memcpy(win->lines[y]->line,  +			    win->lines[y + 1]->line,  +			    win->maxx * __LDATASIZE); +		__touchline(win, y, 0, win->maxx - 1, 0); +	} + +	if (win->orig == NULL) +		win->lines[y] = temp; +	else +		temp = win->lines[y]; + +	for(i = 0; i < win->maxx; i++) { +		temp->line[i].ch = ' '; +		temp->line[i].attr = 0; +	} +	__touchline(win, y, 0, win->maxx - 1, 0); +	if (win->orig == NULL) +		__id_subwins(win); +	return (OK); +} diff --git a/lib/libcurses/delwin.c b/lib/libcurses/delwin.c new file mode 100644 index 000000000000..7310db8588ca --- /dev/null +++ b/lib/libcurses/delwin.c @@ -0,0 +1,80 @@ +/* + * Copyright (c) 1981, 1993, 1994 + *	The 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 sccsid[] = "@(#)delwin.c	8.2 (Berkeley) 5/4/94"; +#endif	/* not lint */ + +#include <stdlib.h> + +#include "curses.h" + +/* + * delwin -- + *	Delete a window and release it back to the system. + */ +int +delwin(win) +	register WINDOW *win; +{ + +	register WINDOW *wp, *np; + +	if (win->orig == NULL) { +		/* +		 * If we are the original window, delete the space for all +		 * the subwindows, the line space and the window space. +		 */ +		free(win->lspace); +		free(win->wspace); +		free(win->lines); +		wp = win->nextp; +		while (wp != win) { +			np = wp->nextp; +			delwin(wp); +			wp = np; +		} +	} else { +		/* +		 * If we are a subwindow, take ourselves out of the list. +		 * NOTE: if we are a subwindow, the minimum list is orig +		 * followed by this subwindow, so there are always at least +		 * two windows in the list. +		 */ +		for (wp = win->nextp; wp->nextp != win; wp = wp->nextp) +			continue; +		wp->nextp = win->nextp; +	} +	free(win); +	return (OK); +} diff --git a/lib/libcurses/erase.c b/lib/libcurses/erase.c new file mode 100644 index 000000000000..42ca68a35a64 --- /dev/null +++ b/lib/libcurses/erase.c @@ -0,0 +1,72 @@ +/* + * Copyright (c) 1981, 1993, 1994 + *	The 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 sccsid[] = "@(#)erase.c	8.2 (Berkeley) 5/4/94"; +#endif	/* not lint */ + +#include "curses.h" + +/* + * werase -- + *	Erases everything on the window. + */ +int +werase(win) +	register WINDOW *win; +{ + +	register int minx, y; +	register __LDATA *sp, *end, *start, *maxx; + +#ifdef DEBUG +	__CTRACE("werase: (%0.2o)\n", win); +#endif +	for (y = 0; y < win->maxy; y++) { +		minx = -1; +		start = win->lines[y]->line; +		end = &start[win->maxx]; +		for (sp = start; sp < end; sp++) +			if (sp->ch != ' ' || sp->attr != 0) { +				maxx = sp;  +				if (minx == -1) +					minx = sp - start; +				sp->ch = ' '; +				sp->attr = 0; +			} +		if (minx != -1) +			__touchline(win, y, minx, maxx - win->lines[y]->line, +			   0); +	} +	return (OK); +} diff --git a/lib/libcurses/getch.c b/lib/libcurses/getch.c new file mode 100644 index 000000000000..6108229708dd --- /dev/null +++ b/lib/libcurses/getch.c @@ -0,0 +1,75 @@ +/* + * Copyright (c) 1981, 1993, 1994 + *	The 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 sccsid[] = "@(#)getch.c	8.2 (Berkeley) 5/4/94"; +#endif	/* not lint */ + +#include "curses.h" + +/* + * wgetch -- + *	Read in a character from the window. + */ +int +wgetch(win) +	register WINDOW *win; +{ +	register int inp, weset; + +	if (!(win->flags & __SCROLLOK) && (win->flags & __FULLWIN) +	    && win->curx == win->maxx - 1 && win->cury == win->maxy - 1) +		return (ERR); +#ifdef DEBUG +	__CTRACE("wgetch: __echoit = %d, __rawmode = %d\n", +	    __echoit, __rawmode); +#endif +	if (__echoit && !__rawmode) { +		cbreak(); +		weset = 1; +	} else +		weset = 0; + +	inp = getchar(); +#ifdef DEBUG +	__CTRACE("wgetch got '%s'\n", unctrl(inp)); +#endif +	if (__echoit) { +		mvwaddch(curscr, +		    win->cury + win->begy, win->curx + win->begx, inp); +		waddch(win, inp); +	} +	if (weset) +		nocbreak(); +	return (inp); +} diff --git a/lib/libcurses/getstr.c b/lib/libcurses/getstr.c new file mode 100644 index 000000000000..daf8e61b7fd7 --- /dev/null +++ b/lib/libcurses/getstr.c @@ -0,0 +1,57 @@ +/* + * Copyright (c) 1981, 1993, 1994 + *	The 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 sccsid[] = "@(#)getstr.c	8.2 (Berkeley) 5/4/94"; +#endif	/* not lint */ + +#include "curses.h" + +/* + * wgetstr -- + *	Get a string starting at (cury, curx). + */ +int +wgetstr(win, str) +	register WINDOW *win; +	register char *str; +{ +	while ((*str = wgetch(win)) != ERR && *str != '\n') +		str++; +	if (*str == ERR) { +		*str = '\0'; +		return (ERR); +	} +	*str = '\0'; +	return (OK); +} diff --git a/lib/libcurses/id_subwins.c b/lib/libcurses/id_subwins.c new file mode 100644 index 000000000000..3528348ff467 --- /dev/null +++ b/lib/libcurses/id_subwins.c @@ -0,0 +1,65 @@ +/* + * Copyright (c) 1981, 1993, 1994 + *	The 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 sccsid[] = "@(#)id_subwins.c	8.2 (Berkeley) 5/4/94"; +#endif	/* not lint */ + +#include "curses.h" + +/* + * __id_subwins -- + *	Re-sync the pointers to lines for all the subwindows. + */ +void +__id_subwins(orig) +	register WINDOW *orig; +{ +	register WINDOW *win; +	register int oy, realy, y; + +	realy = orig->begy + orig->cury; +	for (win = orig->nextp; win != orig; win = win->nextp) { +		/* +		 * If the window ends before our current position, don't need +		 * to do anything. +		 */ +		if (win->begy + win->maxy <= realy) +			continue; + +		oy = orig->cury; +		for (y = realy - win->begy; y < win->maxy; y++, oy++) +			win->lines[y]->line =  +				&orig->lines[oy]->line[win->ch_off]; +	} +} diff --git a/lib/libcurses/idlok.c b/lib/libcurses/idlok.c new file mode 100644 index 000000000000..4d3bb5926979 --- /dev/null +++ b/lib/libcurses/idlok.c @@ -0,0 +1,54 @@ +/* + * Copyright (c) 1981, 1993, 1994 + *	The 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 sccsid[] = "@(#)idlok.c	8.2 (Berkeley) 5/4/94"; +#endif	/* not lint */ + +#include "curses.h" + +/* + * idlok -- + *	Turn on and off using insert/deleteln sequences for the + *	given window. + */ +void +idlok(win, bf) +	WINDOW *win; +	int bf; +{ +	if (bf) +		win->flags |= __IDLINE; +	else +		win->flags &= ~__IDLINE; +} diff --git a/lib/libcurses/initscr.c b/lib/libcurses/initscr.c new file mode 100644 index 000000000000..1af8b6f34ea5 --- /dev/null +++ b/lib/libcurses/initscr.c @@ -0,0 +1,95 @@ +/* + * Copyright (c) 1981, 1993, 1994 + *	The 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 sccsid[] = "@(#)initscr.c	8.2 (Berkeley) 5/4/94"; +#endif	/* not lint */ + +#include <signal.h> +#include <stdlib.h> + +#include "curses.h" + +/* + * initscr -- + *	Initialize the current and standard screen. + */ +WINDOW * +initscr() +{ +	register char *sp; + +#ifdef DEBUG +	__CTRACE("initscr\n"); +#endif +	__echoit = 1; +        __pfast = __rawmode = __noqch = 0; + +	if (gettmode() == ERR) +		return (NULL); + +	/* +	 * If My_term is set, or can't find a terminal in the environment, +	 * use Def_term. +	 */ +	if (My_term || (sp = getenv("TERM")) == NULL) +		sp = Def_term; +	if (setterm(sp) == ERR) +		return (NULL); + +	/* Need either homing or cursor motion for refreshes */ +	if (!HO && !CM)  +		return (NULL); + +	if (curscr != NULL) +		delwin(curscr); +	if ((curscr = newwin(LINES, COLS, 0, 0)) == ERR) +		return (NULL); +	clearok(curscr, 1); + +	if (stdscr != NULL) +		delwin(stdscr); +	if ((stdscr = newwin(LINES, COLS, 0, 0)) == ERR) { +		delwin(curscr); +		return (NULL); +	} + +	__set_stophandler(); + +#ifdef DEBUG +	__CTRACE("initscr: LINES = %d, COLS = %d\n", LINES, COLS); +#endif +	__startwin(); + +	return (stdscr); +} diff --git a/lib/libcurses/insch.c b/lib/libcurses/insch.c new file mode 100644 index 000000000000..36cc0dee8940 --- /dev/null +++ b/lib/libcurses/insch.c @@ -0,0 +1,74 @@ +/* + * Copyright (c) 1981, 1993, 1994 + *	The 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 sccsid[] = "@(#)insch.c	8.2 (Berkeley) 5/4/94"; +#endif	/* not lint */ + +#include <string.h> + +#include "curses.h" + +/* + * winsch -- + *	Do an insert-char on the line, leaving (cury, curx) unchanged. + */ +int +winsch(win, ch) +	register WINDOW *win; +	int ch; +{ + +	register __LDATA *end, *temp1, *temp2; + +	end = &win->lines[win->cury]->line[win->curx]; +	temp1 = &win->lines[win->cury]->line[win->maxx - 1]; +	temp2 = temp1 - 1; +	while (temp1 > end) { +		(void)memcpy(temp1, temp2, sizeof(__LDATA)); +		temp1--, temp2--; +	} +	temp1->ch = ch; +	temp1->attr &= ~__STANDOUT; +	__touchline(win, win->cury, win->curx, win->maxx - 1, 0); +	if (win->cury == LINES - 1 &&  +	    (win->lines[LINES - 1]->line[COLS - 1].ch != ' ' || +	    win->lines[LINES -1]->line[COLS - 1].attr != 0)) +		if (win->flags & __SCROLLOK) { +			wrefresh(win); +			scroll(win); +			win->cury--; +		} else +			return (ERR); +	return (OK); +} diff --git a/lib/libcurses/insertln.c b/lib/libcurses/insertln.c new file mode 100644 index 000000000000..c2179f0f187f --- /dev/null +++ b/lib/libcurses/insertln.c @@ -0,0 +1,82 @@ +/* + * Copyright (c) 1981, 1993, 1994 + *	The 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 sccsid[] = "@(#)insertln.c	8.2 (Berkeley) 5/4/94"; +#endif	/* not lint */ + +#include <string.h> + +#include "curses.h" + +/* + * winsertln -- + *	Do an insert-line on the window, leaving (cury, curx) unchanged. + */ +int +winsertln(win) +	register WINDOW *win; +{ + +	register int y, i; +	register __LINE *temp; + +#ifdef DEBUG +	__CTRACE("insertln: (%0.2o)\n", win); +#endif +	if (win->orig == NULL) +		temp = win->lines[win->maxy - 1]; +	for (y = win->maxy - 1; y > win->cury; --y) { +		win->lines[y]->flags &= ~__ISPASTEOL; +		win->lines[y - 1]->flags &= ~__ISPASTEOL; +		if (win->orig == NULL) +			win->lines[y] = win->lines[y - 1]; +		else +			(void)memcpy(win->lines[y]->line,  +			    win->lines[y - 1]->line,  +			    win->maxx * __LDATASIZE); +		__touchline(win, y, 0, win->maxx - 1, 0); +	} +	if (win->orig == NULL) +		win->lines[y] = temp; +	else +		temp = win->lines[y]; +	for(i = 0; i < win->maxx; i++) { +		temp->line[i].ch = ' '; +		temp->line[i].attr = 0; +	} +	__touchline(win, y, 0, win->maxx - 1, 0); +	if (win->orig == NULL) +		__id_subwins(win); +	return (OK); +} diff --git a/lib/libcurses/move.c b/lib/libcurses/move.c new file mode 100644 index 000000000000..1e22fb0648de --- /dev/null +++ b/lib/libcurses/move.c @@ -0,0 +1,62 @@ +/* + * Copyright (c) 1981, 1993, 1994 + *	The 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 sccsid[] = "@(#)move.c	8.2 (Berkeley) 5/4/94"; +#endif	/* not lint */ + +#include "curses.h" + +/* + * wmove -- + *	Moves the cursor to the given point. + */ +int +wmove(win, y, x) +	register WINDOW *win; +	register int y, x; +{ + +#ifdef DEBUG +	__CTRACE("wmove: (%d, %d)\n", y, x); +#endif +	if (x < 0 || y < 0) +		return (ERR); +	if (x >= win->maxx || y >= win->maxy) +		return (ERR); +	win->curx = x; +	win->lines[win->cury]->flags &= ~__ISPASTEOL; +	win->cury = y; +	win->lines[y]->flags &= ~__ISPASTEOL; +	return (OK); +} diff --git a/lib/libcurses/mvwin.c b/lib/libcurses/mvwin.c new file mode 100644 index 000000000000..1471b27e1868 --- /dev/null +++ b/lib/libcurses/mvwin.c @@ -0,0 +1,77 @@ +/* + * Copyright (c) 1981, 1993, 1994 + *	The 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 sccsid[] = "@(#)mvwin.c	8.2 (Berkeley) 5/4/94"; +#endif	/* not lint */ + +#include "curses.h" + +/* + * mvwin -- + *	Relocate the starting position of a window. + */ +int +mvwin(win, by, bx) +	register WINDOW *win; +	register int by, bx; +{ +	register WINDOW *orig; +	register int dy, dx; + +	if (by + win->maxy > LINES || bx + win->maxx > COLS) +		return (ERR); +	dy = by - win->begy; +	dx = bx - win->begx; +	orig = win->orig; +	if (orig == NULL) { +		orig = win; +		do { +			win->begy += dy; +			win->begx += dx; +			__swflags(win); +			win = win->nextp; +		} while (win != orig); +	} else { +		if (by < orig->begy || win->maxy + dy > orig->maxy) +			return (ERR); +		if (bx < orig->begx || win->maxx + dx > orig->maxx) +			return (ERR); +		win->begy = by; +		win->begx = bx; +		__swflags(win); +		__set_subwin(orig, win); +	} +	__touchwin(win); +	return (OK); +} diff --git a/lib/libcurses/newwin.c b/lib/libcurses/newwin.c new file mode 100644 index 000000000000..8f09cbf7966a --- /dev/null +++ b/lib/libcurses/newwin.c @@ -0,0 +1,244 @@ +/* + * Copyright (c) 1981, 1993, 1994 + *	The 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 sccsid[] = "@(#)newwin.c	8.3 (Berkeley) 7/27/94"; +#endif	/* not lint */ + +#include <stdlib.h> + +#include "curses.h" + +#undef	nl		/* Don't need it here, and it interferes. */ + +static WINDOW 	*__makenew __P((int, int, int, int, int)); + +void	 __set_subwin __P((WINDOW *, WINDOW *)); + +/* + * newwin -- + *	Allocate space for and set up defaults for a new window. + */ +WINDOW * +newwin(nl, nc, by, bx) +	register int nl, nc, by, bx; +{ +	register WINDOW *win; +	register __LINE *lp; +	register int  i, j; +	register __LDATA *sp; + +	if (nl == 0) +		nl = LINES - by; +	if (nc == 0) +		nc = COLS - bx; + +	if ((win = __makenew(nl, nc, by, bx, 0)) == NULL) +		return (NULL); + +	win->nextp = win; +	win->ch_off = 0; +	win->orig = NULL; + +#ifdef DEBUG +	__CTRACE("newwin: win->ch_off = %d\n", win->ch_off); +#endif + +	for (i = 0; i < nl; i++) { +		lp = win->lines[i]; +		lp->flags = 0; +		for (sp = lp->line, j = 0; j < nc; j++, sp++) { +			sp->ch = ' '; +			sp->attr = 0; +		} +		lp->hash = __hash((char *) lp->line, nc * __LDATASIZE); +	} +	return (win); +} + +WINDOW * +subwin(orig, nl, nc, by, bx) +	register WINDOW *orig; +	register int by, bx, nl, nc; +{ +	int i; +	__LINE *lp; +	register WINDOW *win; + +	/* Make sure window fits inside the original one. */ +#ifdef	DEBUG +	__CTRACE("subwin: (%0.2o, %d, %d, %d, %d)\n", orig, nl, nc, by, bx); +#endif +	if (by < orig->begy || bx < orig->begx +	    || by + nl > orig->maxy + orig->begy +	    || bx + nc > orig->maxx + orig->begx) +		return (NULL); +	if (nl == 0) +		nl = orig->maxy + orig->begy - by; +	if (nc == 0) +		nc = orig->maxx + orig->begx - bx; +	if ((win = __makenew(nl, nc, by, bx, 1)) == NULL) +		return (NULL); +	win->nextp = orig->nextp; +	orig->nextp = win; +	win->orig = orig; + +	/* Initialize flags here so that refresh can also use __set_subwin. */ +	for (lp = win->lspace, i = 0; i < win->maxy; i++, lp++) +		lp->flags = 0; +	__set_subwin(orig, win); +	return (win); +} + +/* + * This code is shared with mvwin(). + */ +void +__set_subwin(orig, win) +	register WINDOW *orig, *win; +{ +	int i; +	__LINE *lp, *olp; + +	win->ch_off = win->begx - orig->begx; +	/*  Point line pointers to line space. */ +	for (lp = win->lspace, i = 0; i < win->maxy; i++, lp++) { +		win->lines[i] = lp; +		olp = orig->lines[i + win->begy]; +		lp->line = &olp->line[win->begx]; +		lp->firstchp = &olp->firstch; +		lp->lastchp = &olp->lastch; +		lp->hash = __hash((char *) lp->line, win->maxx * __LDATASIZE); +	} + +#ifdef DEBUG +	__CTRACE("__set_subwin: win->ch_off = %d\n", win->ch_off); +#endif +} + +/* + * __makenew -- + *	Set up a window buffer and returns a pointer to it. + */ +static WINDOW * +__makenew(nl, nc, by, bx, sub) +	register int by, bx, nl, nc; +	int sub; +{ +	register WINDOW *win; +	register __LINE *lp; +	int i; +	 + +#ifdef	DEBUG +	__CTRACE("makenew: (%d, %d, %d, %d)\n", nl, nc, by, bx); +#endif +	if ((win = malloc(sizeof(*win))) == NULL) +		return (NULL); +#ifdef DEBUG +	__CTRACE("makenew: nl = %d\n", nl); +#endif + +	/*  +	 * Set up line pointer array and line space. +	 */ +	if ((win->lines = malloc (nl * sizeof(__LINE *))) == NULL) { +		free(win); +		return NULL; +	} +	if ((win->lspace = malloc (nl * sizeof(__LINE))) == NULL) { +		free (win); +		free (win->lines); +		return NULL; +	} + +	/* Don't allocate window and line space if it's a subwindow */ +	if (!sub) { +		/* +		 * Allocate window space in one chunk. +		 */ +		if ((win->wspace =  +		    malloc(nc * nl * sizeof(__LDATA))) == NULL) { +			free(win->lines); +			free(win->lspace); +			free(win); +			return NULL; +		} +		 +		/* +		 * Point line pointers to line space, and lines themselves into +		 * window space. +		 */ +		for (lp = win->lspace, i = 0; i < nl; i++, lp++) { +			win->lines[i] = lp; +			lp->line = &win->wspace[i * nc]; +			lp->firstchp = &lp->firstch; +			lp->lastchp = &lp->lastch; +			lp->firstch = 0; +			lp->lastch = 0; +		} +	} +#ifdef DEBUG +	__CTRACE("makenew: nc = %d\n", nc); +#endif +	win->cury = win->curx = 0; +	win->maxy = nl; +	win->maxx = nc; + +	win->begy = by; +	win->begx = bx; +	win->flags = 0; +	__swflags(win); +#ifdef DEBUG +	__CTRACE("makenew: win->flags = %0.2o\n", win->flags); +	__CTRACE("makenew: win->maxy = %d\n", win->maxy); +	__CTRACE("makenew: win->maxx = %d\n", win->maxx); +	__CTRACE("makenew: win->begy = %d\n", win->begy); +	__CTRACE("makenew: win->begx = %d\n", win->begx); +#endif +	return (win); +} + +void +__swflags(win) +	register WINDOW *win; +{ +	win->flags &= ~(__ENDLINE | __FULLWIN | __SCROLLWIN | __LEAVEOK); +	if (win->begx + win->maxx == COLS) { +		win->flags |= __ENDLINE; +		if (win->begx == 0 && win->maxy == LINES && win->begy == 0) +			win->flags |= __FULLWIN; +		if (win->begy + win->maxy == LINES) +			win->flags |= __SCROLLWIN; +	} +} diff --git a/lib/libcurses/overlay.c b/lib/libcurses/overlay.c new file mode 100644 index 000000000000..9f35c79e3fb8 --- /dev/null +++ b/lib/libcurses/overlay.c @@ -0,0 +1,82 @@ +/* + * Copyright (c) 1981, 1993, 1994 + *	The 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 sccsid[] = "@(#)overlay.c	8.2 (Berkeley) 5/4/94"; +#endif	/* not lint */ + +#include <ctype.h> + +#include "curses.h" + +/* + * overlay -- + *	Writes win1 on win2 non-destructively. + */ +int +overlay(win1, win2) +	register WINDOW *win1, *win2; +{ + +	register int x, y, y1, y2, endy, endx, starty, startx; +	register __LDATA *sp, *end; + +#ifdef DEBUG +	__CTRACE("overlay: (%0.2o, %0.2o);\n", win1, win2); +#endif +	starty = max(win1->begy, win2->begy); +	startx = max(win1->begx, win2->begx); +	endy = min(win1->maxy + win1->begy, win2->maxy + win2->begx); +	endx = min(win1->maxx + win1->begx, win2->maxx + win2->begx); +#ifdef DEBUG +	__CTRACE("overlay: from (%d,%d) to (%d,%d)\n", +	    starty, startx, endy, endx); +#endif +	if (starty >= endy || startx >= endx) +		return (OK); +	y1 = starty - win1->begy; +	y2 = starty - win2->begy; +	for (y = starty; y < endy; y++, y1++, y2++) { +		end = &win1->lines[y1]->line[endx - win1->begx]; +		x = startx - win2->begx; +		for (sp = &win1->lines[y1]->line[startx - win1->begx];  +		     sp < end; sp++) { +			if (!isspace(sp->ch)) { +				wmove(win2, y2, x); +				__waddch(win2, sp); +			} +			x++; +		} +	} +	return (OK); +} diff --git a/lib/libcurses/overwrite.c b/lib/libcurses/overwrite.c new file mode 100644 index 000000000000..e2d91bd0a8c5 --- /dev/null +++ b/lib/libcurses/overwrite.c @@ -0,0 +1,76 @@ +/* + * Copyright (c) 1981, 1993, 1994 + *	The 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 sccsid[] = "@(#)overwrite.c	8.2 (Berkeley) 5/4/94"; +#endif	/* not lint */ + +#include <ctype.h> +#include <string.h> + +#include "curses.h" + +/* + * overwrite -- + *	Writes win1 on win2 destructively. + */ +int +overwrite(win1, win2) +	register WINDOW *win1, *win2; +{ +	register int x, y, endy, endx, starty, startx; + +#ifdef DEBUG +	__CTRACE("overwrite: (%0.2o, %0.2o);\n", win1, win2); +#endif +	starty = max(win1->begy, win2->begy); +	startx = max(win1->begx, win2->begx); +	endy = min(win1->maxy + win1->begy, win2->maxy + win2->begx); +	endx = min(win1->maxx + win1->begx, win2->maxx + win2->begx); +	if (starty >= endy || startx >= endx) +		return (OK); +#ifdef DEBUG +	__CTRACE("overwrite: from (%d, %d) to (%d, %d)\n", +	    starty, startx, endy, endx); +#endif +	x = endx - startx; +	for (y = starty; y < endy; y++) { +		(void)memcpy( +		    &win2->lines[y - win2->begy]->line[startx - win2->begx],  +		    &win1->lines[y - win1->begy]->line[startx - win1->begx], +		    x * __LDATASIZE); +		__touchline(win2, y, startx - win2->begx, endx - win2->begx, +		    0); +	} +	return (OK); +} diff --git a/lib/libcurses/printw.c b/lib/libcurses/printw.c new file mode 100644 index 000000000000..ae6ea49dabf2 --- /dev/null +++ b/lib/libcurses/printw.c @@ -0,0 +1,200 @@ +/* + * Copyright (c) 1981, 1993, 1994 + *	The 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 sccsid[] = "@(#)printw.c	8.3 (Berkeley) 5/4/94"; +#endif	/* not lint */ + +#ifdef __STDC__ +#include <stdarg.h> +#else +#include <varargs.h> +#endif + +#include "curses.h" + +/* + * printw and friends. + * + * These routines make nonportable assumptions about varargs if __STDC__ + * is not in effect. + */ + +static int __winwrite __P((void *, const char *, int)); + +/* + * printw -- + *	Printf on the standard screen. + */ +int +#ifdef __STDC__ +printw(const char *fmt, ...) +#else +printw(fmt, va_alist) +	char *fmt; +	va_dcl +#endif +{ +	va_list ap; +	int ret; + +#ifdef __STDC__ +	va_start(ap, fmt); +#else +	va_start(ap); +#endif +	ret = vwprintw(stdscr, fmt, ap); +	va_end(ap); +	return (ret); +} + +/* + * wprintw -- + *	Printf on the given window. + */ +int +#ifdef __STDC__ +wprintw(WINDOW * win, const char *fmt, ...) +#else +wprintw(win, fmt, va_alist) +	WINDOW *win; +	char *fmt; +	va_dcl +#endif +{ +	va_list ap; +	int ret; + +#ifdef __STDC__ +	va_start(ap, fmt); +#else +	va_start(ap); +#endif +	ret = vwprintw(win, fmt, ap); +	va_end(ap); +	return (ret); +} + +/* + * mvprintw, mvwprintw -- + *	Implement the mvprintw commands.  Due to the variable number of + *	arguments, they cannot be macros.  Sigh.... + */ +int +#ifdef __STDC__ +mvprintw(register int y, register int x, const char *fmt, ...) +#else +mvprintw(y, x, fmt, va_alist) +	register int y, x; +	char *fmt; +	va_dcl +#endif +{ +	va_list ap; +	int ret; + +#ifdef __STDC__ +	va_start(ap, fmt); +#else +	va_start(ap); +#endif +	if (move(y, x) != OK) +		return (ERR); +	ret = vwprintw(stdscr, fmt, ap); +	va_end(ap); +	return (ret); +} + +int +#ifdef __STDC__ +mvwprintw(register WINDOW * win, register int y, register int x, +    const char *fmt, ...) +#else +mvwprintw(win, y, x, fmt, va_alist) +	register WINDOW *win; +	register int y, x; +	char *fmt; +	va_dcl +#endif +{ +	va_list ap; +	int ret; + +#ifdef __STDC__ +	va_start(ap, fmt); +#else +	va_start(ap); +#endif +	if (wmove(win, y, x) != OK) +		return (ERR); + +	ret = vwprintw(win, fmt, ap); +	va_end(ap); +	return (ret); +} + +/* + * Internal write-buffer-to-window function. + */ +static int +__winwrite(cookie, buf, n) +	void *cookie; +	register const char *buf; +	int n; +{ +	register WINDOW *win; +	register int c; + +	for (c = n, win = cookie; --c >= 0;) +		if (waddch(win, *buf++) == ERR) +			return (-1); +	return (n); +} + +/* + * vwprintw -- + *	This routine actually executes the printf and adds it to the window. + */ +int +vwprintw(win, fmt, ap) +	WINDOW *win; +	const char *fmt; +	va_list ap; +{ +	FILE *f; + +	if ((f = funopen(win, NULL, __winwrite, NULL, NULL)) == NULL) +		return (ERR); +	(void)vfprintf(f, fmt, ap); +	return (fclose(f) ? ERR : OK); +} diff --git a/lib/libcurses/putchar.c b/lib/libcurses/putchar.c new file mode 100644 index 000000000000..2ed5bb4755cc --- /dev/null +++ b/lib/libcurses/putchar.c @@ -0,0 +1,49 @@ +/* + * Copyright (c) 1981, 1993, 1994 + *	The 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 sccsid[] = "@(#)putchar.c	8.2 (Berkeley) 5/4/94"; +#endif	/* not lint */ + +#include "curses.h" + +void +__cputchar(ch) +	int ch; +{ + +#ifdef DEBUG +	__CTRACE("__cputchar: %s\n", unctrl(ch)); +#endif +	(void)putchar(ch); +} diff --git a/lib/libcurses/refresh.c b/lib/libcurses/refresh.c new file mode 100644 index 000000000000..3271bd9101ec --- /dev/null +++ b/lib/libcurses/refresh.c @@ -0,0 +1,827 @@ +/* + * Copyright (c) 1981, 1993, 1994 + *	The 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 sccsid[] = "@(#)refresh.c	8.7 (Berkeley) 8/13/94"; +#endif /* not lint */ + +#include <string.h> + +#include "curses.h" + +static int curwin; +static short ly, lx; + +static void	domvcur __P((int, int, int, int)); +static int	makech __P((WINDOW *, int)); +static void	quickch __P((WINDOW *)); +static void	scrolln __P((WINDOW *, int, int, int, int, int)); + +/* + * wrefresh -- + *	Make the current screen look like "win" over the area coverd by + *	win. + */ +int +wrefresh(win) +	register WINDOW *win; +{ +	register __LINE *wlp; +	register int retval; +	register short wy; +	int dnum; + +	/* Initialize loop parameters. */ +	ly = curscr->cury; +	lx = curscr->curx; +	wy = 0; +	curwin = (win == curscr); + +	if (!curwin) +		for (wy = 0; wy < win->maxy; wy++) { +			wlp = win->lines[wy]; +			if (wlp->flags & __ISDIRTY) +				wlp->hash = __hash((char *)wlp->line, +				    win->maxx * __LDATASIZE); +		} + +	if (win->flags & __CLEAROK || curscr->flags & __CLEAROK || curwin) { +		if ((win->flags & __FULLWIN) || curscr->flags & __CLEAROK) { +			tputs(CL, 0, __cputchar); +			ly = 0; +			lx = 0; +			if (!curwin) { +				curscr->flags &= ~__CLEAROK; +				curscr->cury = 0; +				curscr->curx = 0; +				werase(curscr); +			} +			__touchwin(win); +		} +		win->flags &= ~__CLEAROK; +	} +	if (!CA) { +		if (win->curx != 0) +			putchar('\n'); +		if (!curwin) +			werase(curscr); +	} +#ifdef DEBUG +	__CTRACE("wrefresh: (%0.2o): curwin = %d\n", win, curwin); +	__CTRACE("wrefresh: \tfirstch\tlastch\n"); +#endif + +#ifndef NOQCH +	if ((win->flags & __FULLWIN) && !curwin) { +		/* +		 * Invoke quickch() only if more than a quarter of the lines +		 * in the window are dirty. +		 */ +		for (wy = 0, dnum = 0; wy < win->maxy; wy++) +			if (win->lines[wy]->flags & (__ISDIRTY | __FORCEPAINT)) +				dnum++; +		if (!__noqch && dnum > (int) win->maxy / 4) +			quickch(win); +	} +#endif + +#ifdef DEBUG +{ int i, j; +		__CTRACE("#####################################\n"); +		for (i = 0; i < curscr->maxy; i++) { +			__CTRACE("C: %d:", i); +			__CTRACE(" 0x%x \n", curscr->lines[i]->hash); +			for (j = 0; j < curscr->maxx; j++) +				__CTRACE("%c", +			           curscr->lines[i]->line[j].ch); +			__CTRACE("\n"); +			for (j = 0; j < curscr->maxx; j++) +				__CTRACE("%x", +			           curscr->lines[i]->line[j].attr); +			__CTRACE("\n"); +			__CTRACE("W: %d:", i); +			__CTRACE(" 0x%x \n", win->lines[i]->hash); +			__CTRACE(" 0x%x ", win->lines[i]->flags); +			for (j = 0; j < win->maxx; j++) +				__CTRACE("%c", +			           win->lines[i]->line[j].ch); +			__CTRACE("\n"); +			for (j = 0; j < win->maxx; j++) +				__CTRACE("%x", +			           win->lines[i]->line[j].attr); +			__CTRACE("\n"); +		} +} +#endif /* DEBUG */ + +	for (wy = 0; wy < win->maxy; wy++) { +#ifdef DEBUG +		__CTRACE("%d\t%d\t%d\n", +		    wy, *win->lines[wy]->firstchp, *win->lines[wy]->lastchp); +#endif +		if (!curwin) +			curscr->lines[wy]->hash = win->lines[wy]->hash; +		if (win->lines[wy]->flags & (__ISDIRTY | __FORCEPAINT)) { +			if (makech(win, wy) == ERR) +				return (ERR); +			else { +				if (*win->lines[wy]->firstchp >= win->ch_off) +					*win->lines[wy]->firstchp = win->maxx + +					    win->ch_off; +				if (*win->lines[wy]->lastchp < win->maxx + +				    win->ch_off) +					*win->lines[wy]->lastchp = win->ch_off; +				if (*win->lines[wy]->lastchp < +				    *win->lines[wy]->firstchp) { +#ifdef DEBUG +					__CTRACE("wrefresh: line %d notdirty \n", wy); +#endif +					win->lines[wy]->flags &= ~__ISDIRTY; +				} +			} + +		} +#ifdef DEBUG +		__CTRACE("\t%d\t%d\n", *win->lines[wy]->firstchp, +			*win->lines[wy]->lastchp); +#endif +	} + +#ifdef DEBUG +	__CTRACE("refresh: ly=%d, lx=%d\n", ly, lx); +#endif + +	if (win == curscr) +		domvcur(ly, lx, win->cury, win->curx); +	else { +		if (win->flags & __LEAVEOK) { +			curscr->cury = ly; +			curscr->curx = lx; +			ly -= win->begy; +			lx -= win->begx; +			if (ly >= 0 && ly < win->maxy && lx >= 0 && +			    lx < win->maxx) { +				win->cury = ly; +				win->curx = lx; +			} else +				win->cury = win->curx = 0; +		} else { +			domvcur(ly, lx, win->cury + win->begy, +			    win->curx + win->begx); +			curscr->cury = win->cury + win->begy; +			curscr->curx = win->curx + win->begx; +		} +	} +	retval = OK; + +	(void)fflush(stdout); +	return (retval); +} + +/* + * makech -- + *	Make a change on the screen. + */ +static int +makech(win, wy) +	register WINDOW *win; +	int wy; +{ +	static __LDATA blank = {' ', 0}; +	__LDATA *nsp, *csp, *cp, *cep; +	u_int force; +	int clsp, nlsp;			/* Last space in lines. */ +	int lch, wx, y; +	char *ce; + +	/* Is the cursor still on the end of the last line? */ +	if (wy > 0 && win->lines[wy - 1]->flags & __ISPASTEOL) { +		domvcur(ly, lx, ly + 1, 0); +		ly++; +		lx = 0; +	} +	wx = *win->lines[wy]->firstchp - win->ch_off; +	if (wx < 0) +		wx = 0; +	else if (wx >= win->maxx) +		return (OK); +	lch = *win->lines[wy]->lastchp - win->ch_off; +	if (lch < 0) +		return (OK); +	else if (lch >= (int) win->maxx) +		lch = win->maxx - 1; +	y = wy + win->begy; + +	if (curwin) +		csp = ␣ +	else +		csp = &curscr->lines[wy + win->begy]->line[wx + win->begx]; + +	nsp = &win->lines[wy]->line[wx]; +	force = win->lines[wy]->flags & __FORCEPAINT; +	win->lines[wy]->flags &= ~__FORCEPAINT; +	if (CE && !curwin) { +		for (cp = &win->lines[wy]->line[win->maxx - 1]; +		     cp->ch == ' ' && cp->attr == 0; cp--) +			if (cp <= win->lines[wy]->line) +				break; +		nlsp = cp - win->lines[wy]->line; +	} +	if (!curwin) +		ce = CE; +	else +		ce = NULL; + +	if (force) { +		if (CM) +			tputs(tgoto(CM, lx, ly), 0, __cputchar); +		else { +			tputs(HO, 0, __cputchar); +			__mvcur(0, 0, ly, lx, 1); +		} +	} + +	while (wx <= lch) { +		if (!force && memcmp(nsp, csp, sizeof(__LDATA)) == 0) { +			if (wx <= lch) { +				while (wx <= lch && +				    memcmp(nsp, csp, sizeof(__LDATA)) == 0) { +					nsp++; +					if (!curwin) +						++csp; +					++wx; +				} +				continue; +			} +			break; +		} +		domvcur(ly, lx, y, wx + win->begx); + +#ifdef DEBUG +		__CTRACE("makech: 1: wx = %d, ly= %d, lx = %d, newy = %d, newx = %d, force =%d\n", +		    wx, ly, lx, y, wx + win->begx, force); +#endif +		ly = y; +		lx = wx + win->begx; +		while ((force || memcmp(nsp, csp, sizeof(__LDATA)) != 0) +		    && wx <= lch) { + +			if (ce != NULL && +			    win->maxx + win->begx == curscr->maxx && +			    wx >= nlsp && nsp->ch == ' ' && nsp->attr == 0) { +				/* Check for clear to end-of-line. */ +				cep = &curscr->lines[wy]->line[win->maxx - 1]; +				while (cep->ch == ' ' && cep->attr == 0) +					if (cep-- <= csp) +						break; +				clsp = cep - curscr->lines[wy]->line - +				       win->begx * __LDATASIZE; +#ifdef DEBUG +			__CTRACE("makech: clsp = %d, nlsp = %d\n", clsp, nlsp); +#endif +				if ((clsp - nlsp >= strlen(CE) +				    && clsp < win->maxx * __LDATASIZE) || +				    wy == win->maxy - 1) { +					if (curscr->flags & __WSTANDOUT) { +						tputs(SE, 0, __cputchar); +						curscr->flags &= ~__WSTANDOUT; +					} +					tputs(CE, 0, __cputchar); +					lx = wx + win->begx; +					while (wx++ <= clsp) { +						csp->ch = ' '; +						csp->attr = 0; +						csp++; +					} +					return (OK); +				} +				ce = NULL; +			} + +			/* +			 * Enter/exit standout mode as appropriate. +			 * XXX +			 * Should use UC if SO/SE not available. +			 */ +			if (nsp->attr & __STANDOUT) { +				if (!(curscr->flags & __WSTANDOUT) && +				    SO != NULL && SE != NULL) { +					tputs(SO, 0, __cputchar); +					curscr->flags |= __WSTANDOUT; +				} +			} else +				if (curscr->flags & __WSTANDOUT && +				    SE != NULL) { +					tputs(SE, 0, __cputchar); +					curscr->flags &= ~__WSTANDOUT; +				} + +			wx++; +			if (wx >= win->maxx && wy == win->maxy - 1 && !curwin) +				if (win->flags & __SCROLLOK) { +					if (curscr->flags & __WSTANDOUT +					    && win->flags & __ENDLINE) +						if (!MS) { +							tputs(SE, 0, +							    __cputchar); +							curscr->flags &= +							    ~__WSTANDOUT; +						} +					if (!(win->flags & __SCROLLWIN)) { +						if (!curwin) { +							csp->attr = nsp->attr; +							putchar(csp->ch = nsp->ch); +						} else +							putchar(nsp->ch); +					} +					if (wx + win->begx < curscr->maxx) { +						domvcur(ly, wx + win->begx, +						    win->begy + win->maxy - 1, +						    win->begx + win->maxx - 1); +					} +					ly = win->begy + win->maxy - 1; +					lx = win->begx + win->maxx - 1; +					return (OK); +				} +			if (wx < win->maxx || wy < win->maxy - 1 || +			    !(win->flags & __SCROLLWIN)) { +				if (!curwin) { +					csp->attr = nsp->attr; +					putchar(csp->ch = nsp->ch); +					csp++; +				} else +					putchar(nsp->ch); +			} +#ifdef DEBUG +			__CTRACE("makech: putchar(%c)\n", nsp->ch & 0177); +#endif +			if (UC && (nsp->attr & __STANDOUT)) { +				putchar('\b'); +				tputs(UC, 0, __cputchar); +			} +			nsp++; +#ifdef DEBUG +		__CTRACE("makech: 2: wx = %d, lx = %d\n", wx, lx); +#endif +		} +		if (lx == wx + win->begx)	/* If no change. */ +			break; +		lx = wx + win->begx; +		if (lx >= COLS && AM) +			lx = COLS - 1; +		else if (wx >= win->maxx) { +			domvcur(ly, lx, ly, win->maxx + win->begx - 1); +			lx = win->maxx + win->begx - 1; +		} + +#ifdef DEBUG +		__CTRACE("makech: 3: wx = %d, lx = %d\n", wx, lx); +#endif +	} + +	/* Don't leave the screen in standout mode. */ +	if (curscr->flags & __WSTANDOUT) { +		tputs(SE, 0, __cputchar); +		curscr->flags &= ~__WSTANDOUT; +	} +	return (OK); +} + +/* + * domvcur -- + *	Do a mvcur, leaving standout mode if necessary. + */ +static void +domvcur(oy, ox, ny, nx) +	int oy, ox, ny, nx; +{ +	if (curscr->flags & __WSTANDOUT && !MS) { +		tputs(SE, 0, __cputchar); +		curscr->flags &= ~__WSTANDOUT; +	} + +	__mvcur(oy, ox, ny, nx, 1); +} + +/* + * Quickch() attempts to detect a pattern in the change of the window + * in order to optimize the change, e.g., scroll n lines as opposed to + * repainting the screen line by line. + */ + +static void +quickch(win) +	WINDOW *win; +{ +#define THRESH		(int) win->maxy / 4 + +	register __LINE *clp, *tmp1, *tmp2; +	register int bsize, curs, curw, starts, startw, i, j; +	int n, target, cur_period, bot, top, sc_region; +	__LDATA buf[1024]; +	u_int blank_hash; + +	/* +	 * Find how many lines from the top of the screen are unchanged. +	 */ +	for (top = 0; top < win->maxy; top++) +		if (win->lines[top]->flags & __FORCEPAINT || +		    win->lines[top]->hash != curscr->lines[top]->hash +		    || memcmp(win->lines[top]->line, +		    curscr->lines[top]->line, +		    win->maxx * __LDATASIZE) != 0) +			break; +		else +			win->lines[top]->flags &= ~__ISDIRTY; +       /* +	* Find how many lines from bottom of screen are unchanged. +	*/ +	for (bot = win->maxy - 1; bot >= 0; bot--) +		if (win->lines[bot]->flags & __FORCEPAINT || +		    win->lines[bot]->hash != curscr->lines[bot]->hash +		    || memcmp(win->lines[bot]->line, +		    curscr->lines[bot]->line, +		    win->maxx * __LDATASIZE) != 0) +			break; +		else +			win->lines[bot]->flags &= ~__ISDIRTY; + +#ifdef NO_JERKINESS +	/* +	 * If we have a bottom unchanged region return.  Scrolling the +	 * bottom region up and then back down causes a screen jitter. +	 * This will increase the number of characters sent to the screen +	 * but it looks better. +	 */ +	if (bot < win->maxy - 1) +		return; +#endif /* NO_JERKINESS */ + +	/* +	 * Search for the largest block of text not changed. +	 * Invariants of the loop: +	 * - Startw is the index of the beginning of the examined block in win. +         * - Starts is the index of the beginning of the examined block in +	 *    curscr. +	 * - Curs is the index of one past the end of the exmined block in win. +	 * - Curw is the index of one past the end of the exmined block in +	 *   curscr. +	 * - bsize is the current size of the examined block. +         */ +	for (bsize = bot - top; bsize >= THRESH; bsize--) { +		for (startw = top; startw <= bot - bsize; startw++) +			for (starts = top; starts <= bot - bsize; +			     starts++) { +				for (curw = startw, curs = starts; +				     curs < starts + bsize; curw++, curs++) +					if (win->lines[curw]->flags & +					    __FORCEPAINT || +					    (win->lines[curw]->hash != +					    curscr->lines[curs]->hash || +				            memcmp(win->lines[curw]->line, +					    curscr->lines[curs]->line, +					    win->maxx * __LDATASIZE) != 0)) +						break; +				if (curs == starts + bsize) +					goto done; +			} +	} + done: +	/* Did not find anything */ +	if (bsize < THRESH) +		return; + +#ifdef DEBUG +	__CTRACE("quickch:bsize=%d,starts=%d,startw=%d,curw=%d,curs=%d,top=%d,bot=%d\n", +		bsize, starts, startw, curw, curs, top, bot); +#endif + +	/* +	 * Make sure that there is no overlap between the bottom and top +	 * regions and the middle scrolled block. +	 */ +	if (bot < curs) +		bot = curs - 1; +	if (top > starts) +		top = starts; + +	n = startw - starts; + +#ifdef DEBUG +		__CTRACE("#####################################\n"); +		for (i = 0; i < curscr->maxy; i++) { +			__CTRACE("C: %d:", i); +			__CTRACE(" 0x%x \n", curscr->lines[i]->hash); +			for (j = 0; j < curscr->maxx; j++) +				__CTRACE("%c", +			           curscr->lines[i]->line[j].ch); +			__CTRACE("\n"); +			for (j = 0; j < curscr->maxx; j++) +				__CTRACE("%x", +			           curscr->lines[i]->line[j].attr); +			__CTRACE("\n"); +			__CTRACE("W: %d:", i); +			__CTRACE(" 0x%x \n", win->lines[i]->hash); +			__CTRACE(" 0x%x ", win->lines[i]->flags); +			for (j = 0; j < win->maxx; j++) +				__CTRACE("%c", +			           win->lines[i]->line[j].ch); +			__CTRACE("\n"); +			for (j = 0; j < win->maxx; j++) +				__CTRACE("%x", +			           win->lines[i]->line[j].attr); +			__CTRACE("\n"); +		} +#endif + +	/* So we don't have to call __hash() each time */ +	for (i = 0; i < win->maxx; i++) { +		buf[i].ch = ' '; +		buf[i].attr = 0; +	} +	blank_hash = __hash((char *) buf, win->maxx * __LDATASIZE); + +	/* +	 * Perform the rotation to maintain the consistency of curscr. +	 * This is hairy since we are doing an *in place* rotation. +	 * Invariants of the loop: +	 * - I is the index of the current line. +	 * - Target is the index of the target of line i. +	 * - Tmp1 points to current line (i). +	 * - Tmp2 and points to target line (target); +	 * - Cur_period is the index of the end of the current period. +	 *   (see below). +	 * +	 * There are 2 major issues here that make this rotation non-trivial: +	 * 1.  Scrolling in a scrolling region bounded by the top +	 *     and bottom regions determined (whose size is sc_region). +	 * 2.  As a result of the use of the mod function, there may be a +	 *     period introduced, i.e., 2 maps to 4, 4 to 6, n-2 to 0, and +	 *     0 to 2, which then causes all odd lines not to be rotated. +	 *     To remedy this, an index of the end ( = beginning) of the +	 *     current 'period' is kept, cur_period, and when it is reached, +	 *     the next period is started from cur_period + 1 which is +	 *     guaranteed not to have been reached since that would mean that +	 *     all records would have been reached. (think about it...). +	 * +	 * Lines in the rotation can have 3 attributes which are marked on the +	 * line so that curscr is consistent with the visual screen. +	 * 1.  Not dirty -- lines inside the scrolled block, top region or +	 *                  bottom region. +	 * 2.  Blank lines -- lines in the differential of the scrolling +	 *		      region adjacent to top and bot regions +	 *                    depending on scrolling direction. +	 * 3.  Dirty line -- all other lines are marked dirty. +	 */ +	sc_region = bot - top + 1; +	i = top; +	tmp1 = curscr->lines[top]; +	cur_period = top; +	for (j = top; j <= bot; j++) { +		target = (i - top + n + sc_region) % sc_region + top; +		tmp2 = curscr->lines[target]; +		curscr->lines[target] = tmp1; +		/* Mark block as clean and blank out scrolled lines. */ +		clp = curscr->lines[target]; +#ifdef DEBUG +		__CTRACE("quickch: n=%d startw=%d curw=%d i = %d target=%d ", +			n, startw, curw, i, target); +#endif +		if ((target >= startw && target < curw) || target < top +		    || target > bot) { +#ifdef DEBUG +			__CTRACE("-- notdirty"); +#endif +			win->lines[target]->flags &= ~__ISDIRTY; +		} else if ((n > 0 && target >= top && target < top + n) || +		           (n < 0 && target <= bot && target > bot + n)) { +			if (clp->hash != blank_hash ||  memcmp(clp->line, +			    buf, win->maxx * __LDATASIZE) !=0) { +				(void)memcpy(clp->line,  buf, +				    win->maxx * __LDATASIZE); +#ifdef DEBUG +				__CTRACE("-- blanked out: dirty"); +#endif +				clp->hash = blank_hash; +				__touchline(win, target, 0, win->maxx - 1, 0); +			} else { +				__touchline(win, target, 0, win->maxx - 1, 0); +#ifdef DEBUG +				__CTRACE(" -- blank line already: dirty"); +#endif +			} +		} else { +#ifdef DEBUG +			__CTRACE(" -- dirty"); +#endif +			__touchline(win, target, 0, win->maxx - 1, 0); +		} +#ifdef DEBUG +		__CTRACE("\n"); +#endif +		if (target == cur_period) { +			i = target + 1; +			tmp1 = curscr->lines[i]; +			cur_period = i; +		} else { +			tmp1 = tmp2; +			i = target; +		} +	} +#ifdef DEBUG +		__CTRACE("$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$\n"); +		for (i = 0; i < curscr->maxy; i++) { +			__CTRACE("C: %d:", i); +			for (j = 0; j < curscr->maxx; j++) +				__CTRACE("%c", +			           curscr->lines[i]->line[j].ch); +			__CTRACE("\n"); +			__CTRACE("W: %d:", i); +			for (j = 0; j < win->maxx; j++) +				__CTRACE("%c", win->lines[i]->line[j].ch); +			__CTRACE("\n"); +		} +#endif +	if (n != 0) { +		WINDOW *wp; +		scrolln(win, starts, startw, curs, bot, top); +		/* +		 * Need to repoint any subwindow lines to the rotated +		 * line structured. +		 */ +		for (wp = win->nextp; wp != win; wp = wp->nextp) +			__set_subwin(win, wp); +	} +} + +/* + * scrolln -- + *	Scroll n lines, where n is starts - startw. + */ +static void +scrolln(win, starts, startw, curs, bot, top) +	WINDOW *win; +	int starts, startw, curs, bot, top; +{ +	int i, oy, ox, n; + +	oy = curscr->cury; +	ox = curscr->curx; +	n = starts - startw; + +	/* +	 * XXX +	 * The initial tests that set __noqch don't let us reach here unless +	 * we have either CS + HO + SF/sf/SR/sr, or AL + DL.  SF/sf and SR/sr +	 * scrolling can only shift the entire scrolling region, not just a +	 * part of it, which means that the quickch() routine is going to be +	 * sadly disappointed in us if we don't have CS as well. +	 * +	 * If CS, HO and SF/sf are set, can use the scrolling region.  Because +	 * the cursor position after CS is undefined, we need HO which gives us +	 * the ability to move to somewhere without knowledge of the current +	 * location of the cursor.  Still call __mvcur() anyway, to update its +	 * idea of where the cursor is. +	 * +	 * When the scrolling region has been set, the cursor has to be at the +	 * last line of the region to make the scroll happen. +	 * +	 * Doing SF/SR or AL/DL appears faster on the screen than either sf/sr +	 * or al/dl, and, some terminals have AL/DL, sf/sr, and CS, but not +	 * SF/SR.  So, if we're scrolling almost all of the screen, try and use +	 * AL/DL, otherwise use the scrolling region.  The "almost all" is a +	 * shameless hack for vi. +	 */ +	if (n > 0) { +		if (CS != NULL && HO != NULL && (SF != NULL || +		    (AL == NULL || DL == NULL || +		    top > 3 || bot + 3 < win->maxy) && sf != NULL)) { +			tputs(__tscroll(CS, top, bot + 1), 0, __cputchar); +			__mvcur(oy, ox, 0, 0, 1); +			tputs(HO, 0, __cputchar); +			__mvcur(0, 0, bot, 0, 1); +			if (SF != NULL) +				tputs(__tscroll(SF, n, 0), 0, __cputchar); +			else +				for (i = 0; i < n; i++) +					tputs(sf, 0, __cputchar); +			tputs(__tscroll(CS, 0, win->maxy), 0, __cputchar); +			__mvcur(bot, 0, 0, 0, 1); +			tputs(HO, 0, __cputchar); +			__mvcur(0, 0, oy, ox, 1); +			return; +		} + +		/* Scroll up the block. */ +		if (SF != NULL && top == 0) { +			__mvcur(oy, ox, bot, 0, 1); +			tputs(__tscroll(SF, n, 0), 0, __cputchar); +		} else if (DL != NULL) { +			__mvcur(oy, ox, top, 0, 1); +			tputs(__tscroll(DL, n, 0), 0, __cputchar); +		} else if (dl != NULL) { +			__mvcur(oy, ox, top, 0, 1); +			for (i = 0; i < n; i++) +				tputs(dl, 0, __cputchar); +		} else if (sf != NULL && top == 0) { +			__mvcur(oy, ox, bot, 0, 1); +			for (i = 0; i < n; i++) +				tputs(sf, 0, __cputchar); +		} else +			abort(); + +		/* Push down the bottom region. */ +		__mvcur(top, 0, bot - n + 1, 0, 1); +		if (AL != NULL) +			tputs(__tscroll(AL, n, 0), 0, __cputchar); +		else if (al != NULL) +			for (i = 0; i < n; i++) +				tputs(al, 0, __cputchar); +		else +			abort(); +		__mvcur(bot - n + 1, 0, oy, ox, 1); +	} else { +		/* +		 * !!! +		 * n < 0 +		 * +		 * If CS, HO and SR/sr are set, can use the scrolling region. +		 * See the above comments for details. +		 */ +		if (CS != NULL && HO != NULL && (SR != NULL || +		    (AL == NULL || DL == NULL || +		    top > 3 || bot + 3 < win->maxy) && sr != NULL)) { +			tputs(__tscroll(CS, top, bot + 1), 0, __cputchar); +			__mvcur(oy, ox, 0, 0, 1); +			tputs(HO, 0, __cputchar); +			__mvcur(0, 0, top, 0, 1); + +			if (SR != NULL) +				tputs(__tscroll(SR, -n, 0), 0, __cputchar); +			else +				for (i = n; i < 0; i++) +					tputs(sr, 0, __cputchar); +			tputs(__tscroll(CS, 0, win->maxy), 0, __cputchar); +			__mvcur(top, 0, 0, 0, 1); +			tputs(HO, 0, __cputchar); +			__mvcur(0, 0, oy, ox, 1); +			return; +		} + +		/* Preserve the bottom lines. */ +		__mvcur(oy, ox, bot + n + 1, 0, 1); +		if (SR != NULL && bot == win->maxy) +			tputs(__tscroll(SR, -n, 0), 0, __cputchar); +		else if (DL != NULL) +			tputs(__tscroll(DL, -n, 0), 0, __cputchar); +		else if (dl != NULL) +		       	for (i = n; i < 0; i++) +				tputs(dl, 0, __cputchar); +		else if (sr != NULL && bot == win->maxy) +		       	for (i = n; i < 0; i++) +				tputs(sr, 0, __cputchar); +		else +			abort(); + +		/* Scroll the block down. */ +		__mvcur(bot + n + 1, 0, top, 0, 1); +		if (AL != NULL) +			tputs(__tscroll(AL, -n, 0), 0, __cputchar); +		else if (al != NULL) +			for (i = n; i < 0; i++) +				tputs(al, 0, __cputchar); +		else +			abort(); +		__mvcur(top, 0, oy, ox, 1); +	} +} diff --git a/lib/libcurses/scanw.c b/lib/libcurses/scanw.c new file mode 100644 index 000000000000..d8d79fd23551 --- /dev/null +++ b/lib/libcurses/scanw.c @@ -0,0 +1,175 @@ +/* + * Copyright (c) 1981, 1993, 1994 + *	The 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 sccsid[] = "@(#)scanw.c	8.3 (Berkeley) 5/4/94"; +#endif	/* not lint */ + +/* + * scanw and friends. + */ + +#ifdef __STDC__ +#include <stdarg.h> +#else +#include <varargs.h> +#endif + +#include "curses.h" + +/* + * scanw -- + *	Implement a scanf on the standard screen. + */ +int +#ifdef __STDC__ +scanw(const char *fmt, ...) +#else +scanw(fmt, va_alist) +	char *fmt; +	va_dcl +#endif +{ +	va_list ap; +	int ret; + +#ifdef __STDC__ +	va_start(ap, fmt); +#else +	va_start(ap); +#endif +	ret = vwscanw(stdscr, fmt, ap); +	va_end(ap); +	return (ret); +} + +/* + * wscanw -- + *	Implements a scanf on the given window. + */ +int +#ifdef __STDC__ +wscanw(WINDOW *win, const char *fmt, ...) +#else +wscanw(win, fmt, va_alist) +	WINDOW *win; +	char *fmt; +	va_dcl +#endif +{ +	va_list ap; +	int ret; + +#ifdef __STDC__ +	va_start(ap, fmt); +#else +	va_start(ap); +#endif +	ret = vwscanw(win, fmt, ap); +	va_end(ap); +	return (ret); +} + +/* + * mvscanw, mvwscanw --  + *	Implement the mvscanw commands.  Due to the variable number of + *	arguments, they cannot be macros.  Another sigh.... + */ +int +#ifdef __STDC__ +mvscanw(register int y, register int x, const char *fmt,...) +#else +mvscanw(y, x, fmt, va_alist) +	register int y, x; +	char *fmt; +	va_dcl +#endif +{ +	va_list ap; +	int ret; + +	if (move(y, x) != OK) +		return (ERR); +#ifdef __STDC__ +	va_start(ap, fmt); +#else +	va_start(ap); +#endif +	ret = vwscanw(stdscr, fmt, ap); +	va_end(ap); +	return (ret); +} + +int +#ifdef __STDC__ +mvwscanw(register WINDOW * win, register int y, register int x, +    const char *fmt, ...) +#else +mvwscanw(win, y, x, fmt, va_alist) +	register WINDOW *win; +	register int y, x; +	char *fmt; +	va_dcl +#endif +{ +	va_list ap; +	int ret; + +	if (move(y, x) != OK) +		return (ERR); +#ifdef __STDC__ +	va_start(ap, fmt); +#else +	va_start(ap); +#endif +	ret = vwscanw(win, fmt, ap); +	va_end(ap); +	return (ret); +} + +/* + * vwscanw -- + *	This routine actually executes the scanf from the window. + */ +int +vwscanw(win, fmt, ap) +	WINDOW *win; +	const char *fmt; +	va_list ap; +{ + +	char buf[1024]; + +	return (wgetstr(win, buf) == OK ? +	    vsscanf(buf, fmt, ap) : ERR); +} diff --git a/lib/libcurses/scroll.c b/lib/libcurses/scroll.c new file mode 100644 index 000000000000..8aad91c02854 --- /dev/null +++ b/lib/libcurses/scroll.c @@ -0,0 +1,71 @@ +/* + * Copyright (c) 1981, 1993, 1994 + *	The 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 sccsid[] = "@(#)scroll.c	8.3 (Berkeley) 5/4/94"; +#endif /* not lint */ + +#include "curses.h" + +/* + * scroll -- + *	Scroll the window up a line. + */ +int +scroll(win) +	register WINDOW *win; +{ +	register int oy, ox; + +#ifdef DEBUG +	__CTRACE("scroll: (%0.2o)\n", win); +#endif + +	if (!(win->flags & __SCROLLOK)) +		return (ERR); + +	getyx(win, oy, ox); +	wmove(win, 0, 0); +	wdeleteln(win); +	wmove(win, oy, ox); + +	if (win == curscr) { +		putchar('\n'); +		if (!NONL) +			win->curx = 0; +#ifdef DEBUG +		__CTRACE("scroll: win == curscr\n"); +#endif +	} +	return (OK); +} diff --git a/lib/libcurses/setterm.c b/lib/libcurses/setterm.c new file mode 100644 index 000000000000..887bcb107764 --- /dev/null +++ b/lib/libcurses/setterm.c @@ -0,0 +1,233 @@ +/* + * Copyright (c) 1981, 1993, 1994 + *	The 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 sccsid[] = "@(#)setterm.c	8.8 (Berkeley) 10/25/94"; +#endif /* not lint */ + +#include <sys/ioctl.h>		/* TIOCGWINSZ on old systems. */ + +#include <stdlib.h> +#include <string.h> +#include <termios.h> +#include <unistd.h> + +#include "curses.h" + +static void zap __P((void)); + +static char	*sflags[] = { +		/*       am   bs   da   eo   hc   in   mi   ms  */ +			&AM, &BS, &DA, &EO, &HC, &IN, &MI, &MS, +		/*	 nc   ns   os   ul   xb   xn   xt   xs   xx  */ +			&NC, &NS, &OS, &UL, &XB, &XN, &XT, &XS, &XX +		}; + +static char	*_PC, +		**sstrs[] = { +		/*	 AL   bc   bt   cd   ce   cl   cm   cr   cs  */ +			&AL, &BC, &BT, &CD, &CE, &CL, &CM, &CR, &CS, +		/*	 dc   DL   dm   do   ed   ei   k0   k1   k2  */ +			&DC, &DL, &DM, &DO, &ED, &EI, &K0, &K1, &K2, +		/*	 k3   k4   k5   k6   k7   k8   k9   ho   ic  */ +			&K3, &K4, &K5, &K6, &K7, &K8, &K9, &HO, &IC, +		/*	 im   ip   kd   ke   kh   kl   kr   ks   ku  */ +			&IM, &IP, &KD, &KE, &KH, &KL, &KR, &KS, &KU, +		/*	 ll   ma   nd   nl    pc   rc   sc   se   SF */ +			&LL, &MA, &ND, &NL, &_PC, &RC, &SC, &SE, &SF, +		/*	 so   SR   ta   te   ti   uc   ue   up   us  */ +			&SO, &SR, &TA, &TE, &TI, &UC, &UE, &UP, &US, +		/*	 vb   vs   ve   al   dl   sf   sr   AL	     */ +			&VB, &VS, &VE, &al, &dl, &sf, &sr, &AL_PARM,  +		/*	 DL	   UP	     DO		 LE	     */ +			&DL_PARM, &UP_PARM, &DOWN_PARM, &LEFT_PARM,  +		/*	 RI					     */ +			&RIGHT_PARM, +		}; + +static char	*aoftspace;		/* Address of _tspace for relocation */ +static char	tspace[2048];		/* Space for capability strings */ + +char *ttytype; + +int +setterm(type) +	register char *type; +{ +	static char genbuf[1024]; +	static char __ttytype[1024]; +	register int unknown; +	struct winsize win; +	char *p; + +#ifdef DEBUG +	__CTRACE("setterm: (\"%s\")\nLINES = %d, COLS = %d\n", +	    type, LINES, COLS); +#endif +	if (type[0] == '\0') +		type = "xx"; +	unknown = 0; +	if (tgetent(genbuf, type) != 1) { +		unknown++; +		strcpy(genbuf, "xx|dumb:"); +	} +#ifdef DEBUG +	__CTRACE("setterm: tty = %s\n", type); +#endif + +	/* Try TIOCGWINSZ, and, if it fails, the termcap entry. */ +	if (ioctl(STDERR_FILENO, TIOCGWINSZ, &win) != -1 && +	    win.ws_row != 0 && win.ws_col != 0) { +		LINES = win.ws_row; +		COLS = win.ws_col; +	}  else { +		LINES = tgetnum("li"); +		COLS = tgetnum("co"); +	} + +	/* POSIX 1003.2 requires that the environment override. */ +	if ((p = getenv("LINES")) != NULL) +		LINES = strtol(p, NULL, 10); +	if ((p = getenv("COLUMNS")) != NULL) +		COLS = strtol(p, NULL, 10); + +	/* +	 * Want cols > 4, otherwise things will fail. +	 */ +	if (COLS <= 4) +		return (ERR); + +#ifdef DEBUG +	__CTRACE("setterm: LINES = %d, COLS = %d\n", LINES, COLS); +#endif +	aoftspace = tspace; +	zap();			/* Get terminal description. */ + +	/* If we can't tab, we can't backtab, either. */ +	if (!GT) +		BT = NULL; + +	/* +	 * Test for cursor motion capbility. +	 * +	 * XXX +	 * This is truly stupid -- historically, tgoto returns "OOPS" if it +	 * can't do cursor motions.  Some systems have been fixed to return +	 * a NULL pointer. +	 */ +	if ((p = tgoto(CM, 0, 0)) == NULL || *p == 'O') { +		CA = 0; +		CM = 0; +	} else +		CA = 1; + +	PC = _PC ? _PC[0] : 0; +	aoftspace = tspace; +	ttytype = longname(genbuf, __ttytype); + +	/* If no scrolling commands, no quick change. */ +	__noqch = +	    (CS == NULL || HO == NULL || +	    SF == NULL && sf == NULL || SR == NULL && sr == NULL) && +	    (AL == NULL && al == NULL || DL == NULL && dl == NULL); + +	return (unknown ? ERR : OK); +} + +/* + * zap -- + *	Gets all the terminal flags from the termcap database. + */ +static void +zap() +{ +	register char *namp, ***sp; +	register char **fp; +	char tmp[3]; +#ifdef DEBUG +	register char	*cp; +#endif +	tmp[2] = '\0'; + +	namp = "ambsdaeohcinmimsncnsosulxbxnxtxsxx"; +	fp = sflags; +	do { +		*tmp = *namp; +		*(tmp + 1) = *(namp + 1); +		*(*fp++) = tgetflag(tmp); +#ifdef DEBUG +		__CTRACE("2.2s = %s\n", namp, *fp[-1] ? "TRUE" : "FALSE"); +#endif +		namp += 2; +		 +	} while (*namp); +	namp = "ALbcbtcdceclcmcrcsdcDLdmdoedeik0k1k2k3k4k5k6k7k8k9hoicimipkdkekhklkrkskullmandnlpcrcscseSFsoSRtatetiucueupusvbvsvealdlsfsrALDLUPDOLERI"; +	sp = sstrs; +	do { +		*tmp = *namp; +		*(tmp + 1) = *(namp + 1); +		*(*sp++) = tgetstr(tmp, &aoftspace); +#ifdef DEBUG +		__CTRACE("2.2s = %s", namp, *sp[-1] == NULL ? "NULL\n" : "\""); +		if (*sp[-1] != NULL) { +			for (cp = *sp[-1]; *cp; cp++) +				__CTRACE("%s", unctrl(*cp)); +			__CTRACE("\"\n"); +		} +#endif +		namp += 2; +	} while (*namp); +	if (XS) +		SO = SE = NULL; +	else { +		if (tgetnum("sg") > 0) +			SO = NULL; +		if (tgetnum("ug") > 0) +			US = NULL; +		if (!SO && US) { +			SO = US; +			SE = UE; +		} +	} +} + +/* + * getcap -- + *	Return a capability from termcap. + */ +char * +getcap(name) +	char *name; +{ +	return (tgetstr(name, &aoftspace)); +} diff --git a/lib/libcurses/standout.c b/lib/libcurses/standout.c new file mode 100644 index 000000000000..8851d63d4462 --- /dev/null +++ b/lib/libcurses/standout.c @@ -0,0 +1,67 @@ +/* + * Copyright (c) 1981, 1993, 1994 + *	The 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 sccsid[] = "@(#)standout.c	8.3 (Berkeley) 8/10/94"; +#endif /* not lint */ + +#include "curses.h" + +/* + * wstandout + *	Enter standout mode. + */ +int +wstandout(win) +	WINDOW *win; +{ +	/* +	 * If standout/standend strings, or can underline, set the +	 * screen standout bit. +	 */ +	if (SO != NULL && SE != NULL || UC != NULL) +		win->flags |= __WSTANDOUT; +	return (1); +} + +/* + * wstandend -- + *	Exit standout mode. + */ +int +wstandend(win) +	WINDOW *win; +{ +	win->flags &= ~__WSTANDOUT; +	return (1); +} diff --git a/lib/libcurses/toucholap.c b/lib/libcurses/toucholap.c new file mode 100644 index 000000000000..955c204147f9 --- /dev/null +++ b/lib/libcurses/toucholap.c @@ -0,0 +1,77 @@ +/* + * Copyright (c) 1981, 1993, 1994 + *	The 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 sccsid[] = "@(#)toucholap.c	8.2 (Berkeley) 5/4/94"; +#endif /* not lint */ + +#include "curses.h" + +/* + * touchoverlap -- + *	Touch, on win2, the part that overlaps with win1. + */ +int +touchoverlap(win1, win2) +	register WINDOW *win1, *win2; +{ +	register int y, endy, endx, starty, startx; + +#ifdef DEBUG +	__CTRACE("touchoverlap: (%0.2o, %0.2o);\n", win1, win2); +#endif +	starty = max(win1->begy, win2->begy); +	startx = max(win1->begx, win2->begx); +	endy = min(win1->maxy + win1->begy, win2->maxy + win2->begx); +	endx = min(win1->maxx + win1->begx, win2->maxx + win2->begx); +#ifdef DEBUG +	__CTRACE("touchoverlap: from (%d,%d) to (%d,%d)\n", +	    starty, startx, endy, endx); +	__CTRACE("touchoverlap: win1 (%d,%d) to (%d,%d)\n", +	    win1->begy, win1->begx, win1->begy + win1->maxy, +	    win1->begx + win1->maxx); +	__CTRACE("touchoverlap: win2 (%d,%d) to (%d,%d)\n", +	    win2->begy, win2->begx, win2->begy + win2->maxy, +	    win2->begx + win2->maxx); +#endif +	if (starty >= endy || startx >= endx) +		return (OK); +	starty -= win2->begy; +	startx -= win2->begx; +	endy -= win2->begy; +	endx -= win2->begx; +	for (--endx, y = starty; y < endy; y++) +		__touchline(win2, y, startx, endx, 0); +	return (OK); +} + diff --git a/lib/libcurses/touchwin.c b/lib/libcurses/touchwin.c new file mode 100644 index 000000000000..36f487e5b8f6 --- /dev/null +++ b/lib/libcurses/touchwin.c @@ -0,0 +1,120 @@ +/* + * Copyright (c) 1981, 1993, 1994 + *	The 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 sccsid[] = "@(#)touchwin.c	8.2 (Berkeley) 5/4/94"; +#endif /* not lint */ + +#include "curses.h" + +/* + * touchline -- + *	Touch a given line. + */ +int +touchline(win, y, sx, ex) +	WINDOW *win; +	register int y, sx, ex; +{ +	return (__touchline(win, y, sx, ex, 1)); +} + + +/* + * touchwin -- + *	Make it look like the whole window has been changed. + */ +int +touchwin(win) +	register WINDOW *win; +{ +	register int y, maxy; + +#ifdef DEBUG +	__CTRACE("touchwin: (%0.2o)\n", win); +#endif +	maxy = win->maxy; +	for (y = 0; y < maxy; y++) +		__touchline(win, y, 0, win->maxx - 1, 1); +	return (OK); +} + + +int +__touchwin(win) +	register WINDOW *win; +{ +	register int y, maxy; + +#ifdef DEBUG +	__CTRACE("touchwin: (%0.2o)\n", win); +#endif +	maxy = win->maxy; +	for (y = 0; y < maxy; y++) +		__touchline(win, y, 0, win->maxx - 1, 0); +	return (OK); +} + +int +__touchline(win, y, sx, ex, force) +	register WINDOW *win; +	register int y, sx, ex; +	int force; +{ +#ifdef DEBUG +	__CTRACE("touchline: (%0.2o, %d, %d, %d, %d)\n", win, y, sx, ex, force); +	__CTRACE("touchline: first = %d, last = %d\n", +	    *win->lines[y]->firstchp, *win->lines[y]->lastchp); +#endif +	if (force) +		win->lines[y]->flags |= __FORCEPAINT; +	sx += win->ch_off; +	ex += win->ch_off; +	if (!(win->lines[y]->flags & __ISDIRTY)) { +		win->lines[y]->flags |= __ISDIRTY; +		*win->lines[y]->firstchp = sx; +		*win->lines[y]->lastchp = ex; +	} else { +		if (*win->lines[y]->firstchp > sx) +			*win->lines[y]->firstchp = sx; +		if (*win->lines[y]->lastchp < ex) +			*win->lines[y]->lastchp = ex; +	} +#ifdef DEBUG +	__CTRACE("touchline: first = %d, last = %d\n", +	    *win->lines[y]->firstchp, *win->lines[y]->lastchp); +#endif +	return (OK); +} + + diff --git a/lib/libcurses/tscroll.c b/lib/libcurses/tscroll.c new file mode 100644 index 000000000000..359b3969c631 --- /dev/null +++ b/lib/libcurses/tscroll.c @@ -0,0 +1,139 @@ +/*- + * Copyright (c) 1992, 1993, 1994 + *	The 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 sccsid[] = "@(#)tscroll.c	8.4 (Berkeley) 7/27/94"; +#endif /* not lint */ + +#include "curses.h" + +#define	MAXRETURNSIZE	64 + +/* + * Routine to perform scrolling.  Derived from tgoto.c in tercamp(3) + * library.  Cap is a string containing printf type escapes to allow + * scrolling.  The following escapes are defined for substituting n: + * + *	%d	as in printf + *	%2	like %2d + *	%3	like %3d + *	%.	gives %c hacking special case characters + *	%+x	like %c but adding x first + * + *	The codes below affect the state but don't use up a value. + * + *	%>xy	if value > x add y + *	%i	increments n + *	%%	gives % + *	%B	BCD (2 decimal digits encoded in one byte) + *	%D	Delta Data (backwards bcd) + * + * all other characters are ``self-inserting''. + */ +char * +__tscroll(cap, n1, n2) +	const char *cap; +	int n1, n2; +{ +	static char result[MAXRETURNSIZE]; +	int c, n; +	char *dp; + +	if (cap == NULL) +		goto err; +	for (n = n1, dp = result; (c = *cap++) != '\0';) { +		if (c != '%') { +			*dp++ = c; +			continue; +		} +		switch (c = *cap++) { +		case 'n': +			n ^= 0140; +			continue; +		case 'd': +			if (n < 10) +				goto one; +			if (n < 100) +				goto two; +			/* FALLTHROUGH */ +		case '3': +			*dp++ = (n / 100) | '0'; +			n %= 100; +			/* FALLTHROUGH */ +		case '2': +two:			*dp++ = n / 10 | '0'; +one:			*dp++ = n % 10 | '0'; +			n = n2; +			continue; +		case '>': +			if (n > *cap++) +				n += *cap++; +			else +				cap++; +			continue; +		case '+': +			n += *cap++; +			/* FALLTHROUGH */ +		case '.': +			*dp++ = n; +			continue; +		case 'i': +			n++; +			continue; +		case '%': +			*dp++ = c; +			continue; +		case 'B': +			n = (n / 10 << 4) + n % 10; +			continue; +		case 'D': +			n = n - 2 * (n % 16); +			continue; +		/* +		 * XXX +		 * System V terminfo files have lots of extra gunk. +		 * The only one we've seen in scrolling strings is +		 * %pN, and it seems to work okay if we ignore it. +		 */ +		case 'p': +			++cap; +			continue; +		default: +			goto err; +		} +	} +	*dp = '\0'; +	return (result); + +err:	return("curses: __tscroll failed"); +} diff --git a/lib/libcurses/tstp.c b/lib/libcurses/tstp.c new file mode 100644 index 000000000000..07debf42fe10 --- /dev/null +++ b/lib/libcurses/tstp.c @@ -0,0 +1,124 @@ +/* + * Copyright (c) 1981, 1993, 1994 + *	The 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 sccsid[] = "@(#)tstp.c	8.3 (Berkeley) 5/4/94"; +#endif /* not lint */ + +#include <errno.h> +#include <signal.h> +#include <termios.h> +#include <unistd.h> + +#include "curses.h" + +/* + * stop_signal_handler -- + *	Handle stop signals. + */ +void +__stop_signal_handler(signo) +	int signo; +{ +	struct termios save; +	sigset_t oset, set; + +	/* Get the current terminal state (which the user may have changed). */ +	if (tcgetattr(STDIN_FILENO, &save)) +		return; + +	/* +	 * Block window change and timer signals.  The latter is because +	 * applications use timers to decide when to repaint the screen. +	 */ +	(void)sigemptyset(&set); +	(void)sigaddset(&set, SIGALRM); +	(void)sigaddset(&set, SIGWINCH); +	(void)sigprocmask(SIG_BLOCK, &set, &oset); +	 +	/* +	 * End the window, which also resets the terminal state to the +	 * original modes. +	 */ +	endwin(); + +	/* Unblock SIGTSTP. */ +	(void)sigemptyset(&set); +	(void)sigaddset(&set, SIGTSTP); +	(void)sigprocmask(SIG_UNBLOCK, &set, NULL); + +	/* Stop ourselves. */ +	__restore_stophandler(); +	(void)kill(0, SIGTSTP); + +	/* Time passes ... */ + +	/* Reset the curses SIGTSTP signal handler. */ +	__set_stophandler(); + +	/* save the new "default" terminal state */ +	(void)tcgetattr(STDIN_FILENO, &__orig_termios); + +	/* Reset the terminal state to the mode just before we stopped. */ +	(void)tcsetattr(STDIN_FILENO, __tcaction ? +	    TCSASOFT | TCSADRAIN : TCSADRAIN, &save); + +	/* Restart the screen. */ +	__startwin(); + +	/* Repaint the screen. */ +	wrefresh(curscr); + +	/* Reset the signals. */ +	(void)sigprocmask(SIG_SETMASK, &oset, NULL); +} + +static void (*otstpfn)() = SIG_DFL; + +/* + * Set the TSTP handler. + */ +void +__set_stophandler() +{ +	otstpfn = signal(SIGTSTP, __stop_signal_handler); +} + +/* + * Restore the TSTP handler. + */ +void +__restore_stophandler() +{ +	(void)signal(SIGTSTP, otstpfn); +} diff --git a/lib/libcurses/tty.c b/lib/libcurses/tty.c new file mode 100644 index 000000000000..db031d50fadf --- /dev/null +++ b/lib/libcurses/tty.c @@ -0,0 +1,281 @@ +/*- + * Copyright (c) 1992, 1993, 1994 + *	The 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 sccsid[] = "@(#)tty.c	8.6 (Berkeley) 1/10/95"; +#endif /* not lint */ + +#include <stdlib.h> +#include <termios.h> +#include <unistd.h> + +#include "curses.h" + +/* + * In general, curses should leave tty hardware settings alone (speed, parity, + * word size).  This is most easily done in BSD by using TCSASOFT on all + * tcsetattr calls.  On other systems, it would be better to get and restore + * those attributes at each change, or at least when stopped and restarted. + * See also the comments in getterm(). + */ +#ifdef TCSASOFT +int __tcaction = 1;			/* Ignore hardware settings. */ +#else +int __tcaction = 0; +#endif + +struct termios __orig_termios, __baset; +static struct termios cbreakt, rawt, *curt; +static int useraw; + +#ifndef	OXTABS +#ifdef	XTABS			/* SMI uses XTABS. */ +#define	OXTABS	XTABS +#else +#define	OXTABS	0 +#endif +#endif + +/* + * gettmode -- + *	Do terminal type initialization. + */ +int +gettmode() +{ +	useraw = 0; +	 +	if (tcgetattr(STDIN_FILENO, &__orig_termios)) +		return (ERR); + +	__baset = __orig_termios; +	__baset.c_oflag &= ~OXTABS; + +	GT = 0;		/* historical. was used before we wired OXTABS off */ +	NONL = (__baset.c_oflag & ONLCR) == 0; + +	/* +	 * XXX +	 * System V and SMI systems overload VMIN and VTIME, such that +	 * VMIN is the same as the VEOF element, and VTIME is the same +	 * as the VEOL element.  This means that, if VEOF was ^D, the +	 * default VMIN is 4.  Majorly stupid. +	 */ +	cbreakt = __baset; +	cbreakt.c_lflag &= ~ICANON; +	cbreakt.c_cc[VMIN] = 1; +	cbreakt.c_cc[VTIME] = 0; + +	rawt = cbreakt; +	rawt.c_iflag &= ~(IGNBRK|BRKINT|PARMRK|INLCR|IGNCR|ICRNL|IXON); +	rawt.c_oflag &= ~OPOST; +	rawt.c_lflag &= ~(ECHO|ECHONL|ICANON|ISIG|IEXTEN); + +	/* +	 * In general, curses should leave hardware-related settings alone. +	 * This includes parity and word size.  Older versions set the tty +	 * to 8 bits, no parity in raw(), but this is considered to be an +	 * artifact of the old tty interface.  If it's desired to change +	 * parity and word size, the TCSASOFT bit has to be removed from the +	 * calls that switch to/from "raw" mode. +	 */ +	if (!__tcaction) { +		rawt.c_iflag &= ~ISTRIP; +		rawt.c_cflag &= ~(CSIZE|PARENB); +		rawt.c_cflag |= CS8; +	} + +	curt = &__baset; +	return (tcsetattr(STDIN_FILENO, __tcaction ? +	    TCSASOFT | TCSADRAIN : TCSADRAIN, curt) ? ERR : OK); +} + +int +raw() +{ +	useraw = __pfast = __rawmode = 1; +	curt = &rawt; +	return (tcsetattr(STDIN_FILENO, __tcaction ? +	    TCSASOFT | TCSADRAIN : TCSADRAIN, curt) ? ERR : OK); +} + +int +noraw() +{ +	useraw = __pfast = __rawmode = 0; +	curt = &__baset; +	return (tcsetattr(STDIN_FILENO, __tcaction ? +	    TCSASOFT | TCSADRAIN : TCSADRAIN, curt) ? ERR : OK); +} + +int +cbreak() +{ + +	__rawmode = 1; +	curt = useraw ? &rawt : &cbreakt; +	return (tcsetattr(STDIN_FILENO, __tcaction ? +	    TCSASOFT | TCSADRAIN : TCSADRAIN, curt) ? ERR : OK); +} + +int +nocbreak() +{ + +	__rawmode = 0; +	curt = useraw ? &rawt : &__baset; +	return (tcsetattr(STDIN_FILENO, __tcaction ? +	    TCSASOFT | TCSADRAIN : TCSADRAIN, curt) ? ERR : OK); +} +	 +int +echo() +{ +	rawt.c_lflag |= ECHO; +	cbreakt.c_lflag |= ECHO; +	__baset.c_lflag |= ECHO; +	 +	__echoit = 1; +	return (tcsetattr(STDIN_FILENO, __tcaction ? +	    TCSASOFT | TCSADRAIN : TCSADRAIN, curt) ? ERR : OK); +} + +int +noecho() +{ +	rawt.c_lflag &= ~ECHO; +	cbreakt.c_lflag &= ~ECHO; +	__baset.c_lflag &= ~ECHO; +	 +	__echoit = 0; +	return (tcsetattr(STDIN_FILENO, __tcaction ? +	    TCSASOFT | TCSADRAIN : TCSADRAIN, curt) ? ERR : OK); +} + +int +nl() +{ +	rawt.c_iflag |= ICRNL; +	rawt.c_oflag |= ONLCR; +	cbreakt.c_iflag |= ICRNL; +	cbreakt.c_oflag |= ONLCR; +	__baset.c_iflag |= ICRNL; +	__baset.c_oflag |= ONLCR; + +	__pfast = __rawmode; +	return (tcsetattr(STDIN_FILENO, __tcaction ? +	    TCSASOFT | TCSADRAIN : TCSADRAIN, curt) ? ERR : OK); +} + +int +nonl() +{ +	rawt.c_iflag &= ~ICRNL; +	rawt.c_oflag &= ~ONLCR; +	cbreakt.c_iflag &= ~ICRNL; +	cbreakt.c_oflag &= ~ONLCR; +	__baset.c_iflag &= ~ICRNL; +	__baset.c_oflag &= ~ONLCR; + +	__pfast = 1; +	return (tcsetattr(STDIN_FILENO, __tcaction ? +	    TCSASOFT | TCSADRAIN : TCSADRAIN, curt) ? ERR : OK); +} + +void +__startwin() +{ +	static char *stdbuf; +	static size_t len; + +	(void)fflush(stdout); + +	/* +	 * Some C libraries default to a 1K buffer when talking to a tty. +	 * With a larger screen, especially across a network, we'd like +	 * to get it to all flush in a single write.  Make it twice as big +	 * as just the characters (so that we have room for cursor motions +	 * and standout information) but no more than 8K. +	 */ +	if (stdbuf == NULL) { +		if ((len = LINES * COLS * 2) > 8192) +			len = 8192; +		if ((stdbuf = malloc(len)) == NULL) +			len = 0; +	} +	(void)setvbuf(stdout, stdbuf, _IOFBF, len); + +	tputs(TI, 0, __cputchar); +	tputs(VS, 0, __cputchar); +} + +int +endwin() +{ +	__restore_stophandler(); + +	if (curscr != NULL) { +		if (curscr->flags & __WSTANDOUT) { +			tputs(SE, 0, __cputchar); +			curscr->flags &= ~__WSTANDOUT; +		} +		__mvcur(curscr->cury, curscr->curx, curscr->maxy - 1, 0, 0); +	} + +	(void)tputs(VE, 0, __cputchar); +	(void)tputs(TE, 0, __cputchar); +	(void)fflush(stdout); +	(void)setvbuf(stdout, NULL, _IOLBF, 0); + +	return (tcsetattr(STDIN_FILENO, __tcaction ? +	    TCSASOFT | TCSADRAIN : TCSADRAIN, &__orig_termios) ? ERR : OK); +} + +/* + * The following routines, savetty and resetty are completely useless and + * are left in only as stubs.  If people actually use them they will almost + * certainly screw up the state of the world. + */ +static struct termios savedtty; +int +savetty() +{ +	return (tcgetattr(STDIN_FILENO, &savedtty) ? ERR : OK); +} + +int +resetty() +{ +	return (tcsetattr(STDIN_FILENO, __tcaction ? +	    TCSASOFT | TCSADRAIN : TCSADRAIN, &savedtty) ? ERR : OK); +} diff --git a/lib/libedit/histedit.h b/lib/libedit/histedit.h new file mode 100644 index 000000000000..95423c6482f5 --- /dev/null +++ b/lib/libedit/histedit.h @@ -0,0 +1,172 @@ +/*- + * Copyright (c) 1992, 1993 + *	The Regents of the University of California.  All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Christos Zoulas of Cornell University. + * + * 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. + * + *	@(#)histedit.h	8.2 (Berkeley) 1/3/94 + */ + +/* + * histedit.h: Line editor and history interface. + */ +#ifndef _h_editline +#define _h_editline + +#include <sys/types.h> +#include <stdio.h> + +/* + * ==== Editing ==== + */ +typedef struct editline EditLine; + +/* + * For user-defined function interface + */ +typedef struct lineinfo { +    __const char *buffer; +    __const char *cursor; +    __const char *lastchar; +} LineInfo; + + +/* + * EditLine editor function return codes. + * For user-defined function interface + */ +#define	CC_NORM		0 +#define	CC_NEWLINE	1 +#define	CC_EOF		2 +#define CC_ARGHACK	3 +#define CC_REFRESH	4 +#define	CC_CURSOR	5 +#define	CC_ERROR	6 +#define CC_FATAL	7 + +/* + * Initialization, cleanup, and resetting + */ +EditLine	*el_init	__P((const char *, FILE *, FILE *)); +void		 el_reset	__P((EditLine *)); +void		 el_end		__P((EditLine *)); + + +/* + * Get a line, a character or push a string back in the input queue + */ +__const char    *el_gets	__P((EditLine *, int *)); +int		 el_getc	__P((EditLine *, char *)); +void		 el_push	__P((EditLine *, const char *)); + +/* + * High level function internals control + * Parses argc, argv array and executes builtin editline commands + */ +int		 el_parse	__P((EditLine *, int, char **));  + +/* + * Low level editline access function + */ +int 		 el_set		__P((EditLine *, int, ...)); + +/* + * el_set/el_get parameters + */ +#define EL_PROMPT	0	/* , el_pfunc_t);		*/ +#define EL_TERMINAL	1	/* , const char *);		*/ +#define EL_EDITOR	2	/* , const char *);		*/ +#define EL_SIGNAL	3	/* , int);			*/ +#define	EL_BIND		4	/* , const char *, ..., NULL);	*/ +#define	EL_TELLTC	5	/* , const char *, ..., NULL);	*/ +#define	EL_SETTC	6	/* , const char *, ..., NULL);	*/ +#define	EL_ECHOTC	7	/* , const char *, ..., NULL);	*/ +#define	EL_SETTY	8	/* , const char *, ..., NULL);	*/ +#define	EL_ADDFN	9	/* , const char *, const char *	*/ +				/* , el_func_t);		*/ +#define EL_HIST		10	/* , hist_fun_t, const char *);	*/ + +/* + * Source named file or $PWD/.editrc or $HOME/.editrc + */ +int		el_source	__P((EditLine *, const char *)); + +/* + * Must be called when the terminal changes size; If EL_SIGNAL + * is set this is done automatically otherwise it is the responsibility + * of the application + */ +void		 el_resize	__P((EditLine *)); + + +/* + * User-defined function interface. + */ +__const LineInfo *el_line	__P((EditLine *)); +int   		  el_insertstr	__P((EditLine *, char *)); +void		  el_deletestr	__P((EditLine *, int)); + +/* + * ==== History ==== + */ + +typedef struct history History; + +typedef struct HistEvent { +    int 	  num; +    __const char *str; +} HistEvent; + +/* + * History access functions. + */ +History *		history_init	__P((void)); +void 			history_end	__P((History *)); + +__const HistEvent *	history		__P((History *, int, ...)); + +#define H_FUNC		 0	/* , UTSL		*/ +#define H_EVENT		 1	/* , const int);	*/ +#define H_FIRST		 2	/* , void);		*/ +#define H_LAST		 3	/* , void);		*/ +#define H_PREV		 4	/* , void);		*/ +#define H_NEXT		 5	/* , void);		*/ +#define H_CURR		 6	/* , void);		*/ +#define H_ADD		 7	/* , const char*);	*/ +#define H_ENTER		 8	/* , const char*);	*/ +#define H_END		 9	/* , void);		*/ +#define H_NEXT_STR	10	/* , const char*);	*/ +#define H_PREV_STR	11	/* , const char*);	*/ +#define H_NEXT_EVENT	12	/* , const int);	*/ +#define H_PREV_EVENT	13	/* , const int);	*/ + +#endif /* _h_editline */ diff --git a/lib/libedit/term.c b/lib/libedit/term.c new file mode 100644 index 000000000000..4b793b7b6642 --- /dev/null +++ b/lib/libedit/term.c @@ -0,0 +1,1451 @@ +/*- + * Copyright (c) 1992, 1993 + *	The Regents of the University of California.  All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Christos Zoulas of Cornell University. + * + * 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. + */ + +#if !defined(lint) && !defined(SCCSID) +static char sccsid[] = "@(#)term.c	8.2 (Berkeley) 4/30/95"; +#endif /* not lint && not SCCSID */ + +/* + * term.c: Editor/termcap-curses interface + *	   We have to declare a static variable here, since the + *	   termcap putchar routine does not take an argument! + */ +#include "sys.h" +#include <stdio.h> +#include <signal.h> +#include <string.h> +#include <stdlib.h> +#include <unistd.h> +#include "termcap.h"	/* XXX: should be <termcap.h> */ +#include <sys/types.h> + +#include "el.h" + +/* + * IMPORTANT NOTE: these routines are allowed to look at the current screen + * and the current possition assuming that it is correct.  If this is not + * true, then the update will be WRONG!  This is (should be) a valid + * assumption... + */ + +#define TC_BUFSIZE 2048 + +#define GoodStr(a) (el->el_term.t_str[a] != NULL && \ +		    el->el_term.t_str[a][0] != '\0') +#define Str(a) el->el_term.t_str[a] +#define Val(a) el->el_term.t_val[a] + +private struct { +    char   *b_name; +    int     b_rate; +} baud_rate[] = { +#ifdef B0 +    { "0", B0 }, +#endif +#ifdef B50 +    { "50", B50 }, +#endif +#ifdef B75 +    { "75", B75 }, +#endif +#ifdef B110 +    { "110", B110 }, +#endif +#ifdef B134 +    { "134", B134 }, +#endif +#ifdef B150 +    { "150", B150 }, +#endif +#ifdef B200 +    { "200", B200 }, +#endif +#ifdef B300 +    { "300", B300 }, +#endif +#ifdef B600 +    { "600", B600 }, +#endif +#ifdef B900 +    { "900", B900 }, +#endif +#ifdef B1200 +    { "1200", B1200 }, +#endif +#ifdef B1800 +    { "1800", B1800 }, +#endif +#ifdef B2400 +    { "2400", B2400 }, +#endif +#ifdef B3600 +    { "3600", B3600 }, +#endif +#ifdef B4800 +    { "4800", B4800 }, +#endif +#ifdef B7200 +    { "7200", B7200 }, +#endif +#ifdef B9600 +    { "9600", B9600 }, +#endif +#ifdef EXTA +    { "19200", EXTA }, +#endif +#ifdef B19200 +    { "19200", B19200 }, +#endif +#ifdef EXTB +    { "38400", EXTB }, +#endif +#ifdef B38400 +    { "38400", B38400 }, +#endif +    { NULL, 0 } +}; + +private struct termcapstr { +    char   *name; +    char   *long_name; +} tstr[] = { + +#define T_al	0 +    {	"al",	"add new blank line"		}, +#define T_bl	1 +    {	"bl",	"audible bell"			}, +#define T_cd	2 +    {	"cd",	"clear to bottom"		}, +#define T_ce	3 +    {	"ce",	"clear to end of line"		}, +#define T_ch	4 +    {	"ch",	"cursor to horiz pos"		}, +#define T_cl	5 +    {	"cl",	"clear screen"			}, +#define	T_dc	6 +    {	"dc",	"delete a character"		}, +#define	T_dl	7 +    {	"dl",	"delete a line"		 	}, +#define	T_dm	8 +    {	"dm",	"start delete mode"		}, +#define	T_ed	9 +    {	"ed",	"end delete mode"		}, +#define	T_ei	10 +    {	"ei",	"end insert mode"		}, +#define	T_fs	11 +    {	"fs",	"cursor from status line"	}, +#define	T_ho	12 +    {	"ho",	"home cursor"			}, +#define	T_ic	13 +    {	"ic",	"insert character"		}, +#define	T_im	14  +    {	"im",	"start insert mode"		}, +#define	T_ip	15 +    {	"ip",	"insert padding"		}, +#define	T_kd	16 +    {	"kd",	"sends cursor down"		}, +#define	T_kl	17 +    {	"kl",	"sends cursor left"		}, +#define T_kr	18 +    {	"kr",	"sends cursor right"		}, +#define T_ku	19 +    {	"ku",	"sends cursor up"		}, +#define T_md	20 +    {	"md",	"begin bold"			}, +#define T_me	21 +    {	"me",	"end attributes"		}, +#define T_nd	22 +    {	"nd",	"non destructive space"	 	}, +#define T_se	23 +    {	"se",	"end standout"			}, +#define T_so	24 +    {	"so",	"begin standout"		}, +#define T_ts	25 +    {	"ts",	"cursor to status line"	 	}, +#define T_up	26 +    {	"up",	"cursor up one"		 	}, +#define T_us	27 +    {	"us",	"begin underline"		}, +#define T_ue	28 +    {	"ue",	"end underline"		 	}, +#define T_vb	29 +    {	"vb",	"visible bell"			}, +#define T_DC	30 +    {	"DC",	"delete multiple chars"	 	}, +#define T_DO	31 +    {	"DO",	"cursor down multiple"		}, +#define T_IC	32 +    {	"IC",	"insert multiple chars"	 	}, +#define T_LE	33 +    {	"LE",	"cursor left multiple"		}, +#define T_RI	34 +    {	"RI",	"cursor right multiple"	 	}, +#define T_UP	35 +    {	"UP",	"cursor up multiple"		}, +#define T_str	36 +    {	NULL,   NULL			 	} +}; + +private struct termcapval { +    char   *name; +    char   *long_name; +} tval[] = { +#define T_pt	0 +    {	"pt",	"has physical tabs"	}, +#define T_li	1 +    {	"li",	"Number of lines"	}, +#define T_co	2 +    {	"co",	"Number of columns"	}, +#define T_km	3 +    {	"km",	"Has meta key"		}, +#define T_xt	4 +    {	"xt",	"Tab chars destructive" }, +#define T_MT	5 +    {	"MT",	"Has meta key"		},	/* XXX? */ +#define T_val	6 +    {	NULL, 	NULL,			} +}; + +/* do two or more of the attributes use me */ + +private	void	term_rebuffer_display	__P((EditLine *)); +private	void	term_free_display	__P((EditLine *)); +private	void	term_alloc_display	__P((EditLine *)); +private	void	term_alloc		__P((EditLine *, +					     struct termcapstr *, char *));  +private void	term_init_arrow		__P((EditLine *)); +private void	term_reset_arrow	__P((EditLine *)); + + +private FILE *term_outfile = NULL;	/* XXX: How do we fix that? */ + + +/* term_setflags(): + *	Set the terminal capability flags + */ +private void +term_setflags(el) +    EditLine *el; +{ +    EL_FLAGS = 0; +    if (el->el_tty.t_tabs)  +	EL_FLAGS |= (Val(T_pt) && !Val(T_xt)) ? TERM_CAN_TAB : 0; + +    EL_FLAGS |= (Val(T_km) || Val(T_MT)) ? TERM_HAS_META : 0; +    EL_FLAGS |= GoodStr(T_ce) ? TERM_CAN_CEOL : 0; +    EL_FLAGS |= (GoodStr(T_dc) || GoodStr(T_DC)) ? TERM_CAN_DELETE : 0; +    EL_FLAGS |= (GoodStr(T_im) || GoodStr(T_ic) || GoodStr(T_IC)) ? +		 TERM_CAN_INSERT : 0; +    EL_FLAGS |= (GoodStr(T_up) || GoodStr(T_UP))  ? TERM_CAN_UP : 0; + +    if (GoodStr(T_me) && GoodStr(T_ue)) +	EL_FLAGS |= (strcmp(Str(T_me), Str(T_ue)) == 0) ? TERM_CAN_ME : 0; +    else +	EL_FLAGS &= ~TERM_CAN_ME; +    if (GoodStr(T_me) && GoodStr(T_se)) +	EL_FLAGS |= (strcmp(Str(T_me), Str(T_se)) == 0) ? TERM_CAN_ME : 0; + + +#ifdef DEBUG_SCREEN +    if (!EL_CAN_UP) { +	(void) fprintf(el->el_errfile, "WARNING: Your terminal cannot move up.\n"); +	(void) fprintf(el->el_errfile, "Editing may be odd for long lines.\n"); +    } +    if (!EL_CAN_CEOL) +	(void) fprintf(el->el_errfile, "no clear EOL capability.\n"); +    if (!EL_CAN_DELETE) +	(void) fprintf(el->el_errfile, "no delete char capability.\n"); +    if (!EL_CAN_INSERT) +	(void) fprintf(el->el_errfile, "no insert char capability.\n"); +#endif /* DEBUG_SCREEN */ +} + + +/* term_init(): + *	Initialize the terminal stuff + */ +protected int +term_init(el) +    EditLine *el; +{ +    el->el_term.t_buf = (char *)  el_malloc(TC_BUFSIZE); +    el->el_term.t_cap = (char *)  el_malloc(TC_BUFSIZE); +    el->el_term.t_fkey = (fkey_t *) el_malloc(4 * sizeof(fkey_t)); +    el->el_term.t_loc = 0; +    el->el_term.t_str = (char **) el_malloc(T_str * sizeof(char*)); +    (void) memset(el->el_term.t_str, 0, T_str * sizeof(char*)); +    el->el_term.t_val = (int *)   el_malloc(T_val * sizeof(int)); +    (void) memset(el->el_term.t_val, 0, T_val * sizeof(char*)); +    term_outfile = el->el_outfile; +    (void) term_set(el, NULL); +    term_init_arrow(el); +    return 0; +} + +/* term_end(): + *	Clean up the terminal stuff + */ +protected void +term_end(el) +    EditLine *el; +{ +    el_free((ptr_t) el->el_term.t_buf); +    el->el_term.t_buf = NULL; +    el_free((ptr_t) el->el_term.t_cap); +    el->el_term.t_cap = NULL; +    el->el_term.t_loc = 0; +    el_free((ptr_t) el->el_term.t_str); +    el->el_term.t_str = NULL; +    el_free((ptr_t) el->el_term.t_val); +    el->el_term.t_val = NULL; +    term_free_display(el); +} + + +/* term_alloc(): + *	Maintain a string pool for termcap strings + */ +private void +term_alloc(el, t, cap) +    EditLine *el; +    struct termcapstr *t; +    char   *cap; +{ +    char    termbuf[TC_BUFSIZE]; +    int     tlen, clen; +    char    **tlist = el->el_term.t_str; +    char    **tmp, **str = &tlist[t - tstr]; + +    if (cap == NULL || *cap == '\0') { +	*str = NULL; +	return; +    } +    else +	clen = strlen(cap); + +    tlen  = *str == NULL ? 0 : strlen(*str); + +    /* +     * New string is shorter; no need to allocate space +     */ +    if (clen <= tlen) { +	(void) strcpy(*str, cap); +	return; +    } + +    /* +     * New string is longer; see if we have enough space to append +     */ +    if (el->el_term.t_loc + 3 < TC_BUFSIZE) { +	(void) strcpy(*str = &el->el_term.t_buf[el->el_term.t_loc], cap); +	el->el_term.t_loc += clen + 1;	/* one for \0 */ +	return; +    } + +    /* +     * Compact our buffer; no need to check compaction, cause we know it +     * fits... +     */ +    tlen = 0; +    for (tmp = tlist; tmp < &tlist[T_str]; tmp++) +	if (*tmp != NULL && *tmp != '\0' && *tmp != *str) { +	    char   *ptr; + +	    for (ptr = *tmp; *ptr != '\0'; termbuf[tlen++] = *ptr++) +		continue; +	    termbuf[tlen++] = '\0'; +	} +    memcpy(el->el_term.t_buf, termbuf, TC_BUFSIZE); +    el->el_term.t_loc = tlen; +    if (el->el_term.t_loc + 3 >= TC_BUFSIZE) { +	(void) fprintf(el->el_errfile, "Out of termcap string space.\n"); +	return; +    } +    (void) strcpy(*str = &el->el_term.t_buf[el->el_term.t_loc], cap); +    el->el_term.t_loc += clen + 1;		/* one for \0 */ +    return; +} /* end term_alloc */ + + +/* term_rebuffer_display(): + *	Rebuffer the display after the screen changed size + */ +private void +term_rebuffer_display(el) +    EditLine *el; +{ +    coord_t *c = &el->el_term.t_size; + +    term_free_display(el); + +    /* make this public, -1 to avoid wraps */ +    c->h = Val(T_co) - 1; +    c->v = (EL_BUFSIZ * 4) / c->h + 1; + +    term_alloc_display(el); +} /* end term_rebuffer_display */ + + +/* term_alloc_display(): + *	Allocate a new display. + */ +private void +term_alloc_display(el) +    EditLine *el; +{ +    int i; +    char  **b; +    coord_t *c = &el->el_term.t_size; + +    b = (char **) el_malloc((size_t) (sizeof(char *) * (c->v + 1))); +    for (i = 0; i < c->v; i++) +	b[i] = (char *) el_malloc((size_t) (sizeof(char) * (c->h + 1))); +    b[c->v] = NULL; +    el->el_display = b; + +    b = (char **) el_malloc((size_t) (sizeof(char *) * (c->v + 1))); +    for (i = 0; i < c->v; i++) +	b[i] = (char *) el_malloc((size_t) (sizeof(char) * (c->h + 1))); +    b[c->v] = NULL; +    el->el_vdisplay = b; + +} /* end term_alloc_display */ + + +/* term_free_display(): + *	Free the display buffers + */ +private void +term_free_display(el) +    EditLine *el; +{ +    char  **b; +    char  **bufp; + +    b = el->el_display; +    el->el_display = NULL; +    if (b != NULL) { +	for (bufp = b; *bufp != NULL; bufp++) +	    el_free((ptr_t) *bufp); +	el_free((ptr_t) b); +    } +    b = el->el_vdisplay; +    el->el_vdisplay = NULL; +    if (b != NULL) { +	for (bufp = b; *bufp != NULL; bufp++) +	    el_free((ptr_t) * bufp); +	el_free((ptr_t) b); +    } +} /* end term_free_display */ + + +/* term_move_to_line(): + *	move to line <where> (first line == 0) + * 	as efficiently as possible + */ +protected void +term_move_to_line(el, where) +    EditLine *el; +    int     where;		 +{ +    int     del, i; + +    if (where == el->el_cursor.v) +	return; + +    if (where > el->el_term.t_size.v) { +#ifdef DEBUG_SCREEN +	(void) fprintf(el->el_errfile,  +		"term_move_to_line: where is ridiculous: %d\r\n", where); +#endif /* DEBUG_SCREEN */ +	return; +    } + +    if ((del = where - el->el_cursor.v) > 0) { +	if ((del > 1) && GoodStr(T_DO)) +	    (void) tputs(tgoto(Str(T_DO), del, del), del, term__putc); +	else { +	    for (i = 0; i < del; i++) +		term__putc('\n'); +	    el->el_cursor.h = 0;	/* because the \n will become \r\n */ +	} +    } +    else {			/* del < 0 */ +	if (GoodStr(T_UP) && (-del > 1 || !GoodStr(T_up))) +	    (void) tputs(tgoto(Str(T_UP), -del, -del), -del, term__putc); +	else { +	    if (GoodStr(T_up)) +		for (i = 0; i < -del; i++) +		    (void) tputs(Str(T_up), 1, term__putc); +	} +    } +    el->el_cursor.v = where;		/* now where is here */ +} /* end term_move_to_line */ + + +/* term_move_to_char(): + *	Move to the character position specified + */ +protected void +term_move_to_char(el, where) +    EditLine *el; +    int     where; +{ +    int     del, i; + +mc_again: +    if (where == el->el_cursor.h) +	return; + +    if (where > (el->el_term.t_size.h + 1)) { +#ifdef DEBUG_SCREEN +	(void) fprintf(el->el_errfile,  +		"term_move_to_char: where is riduculous: %d\r\n", where); +#endif /* DEBUG_SCREEN */ +	return; +    } + +    if (!where) {		/* if where is first column */ +	term__putc('\r');	/* do a CR */ +	el->el_cursor.h = 0; +	return; +    } + +    del = where - el->el_cursor.h; + +    if ((del < -4 || del > 4) && GoodStr(T_ch)) +	/* go there directly */ +	(void) tputs(tgoto(Str(T_ch), where, where), where, term__putc); +    else { +	if (del > 0) {		/* moving forward */ +	    if ((del > 4) && GoodStr(T_RI)) +		(void) tputs(tgoto(Str(T_RI), del, del), del, term__putc); +	    else { +		if (EL_CAN_TAB) {	/* if I can do tabs, use them */ +		    if ((el->el_cursor.h & 0370) != (where & 0370)) { +			/* if not within tab stop */ +			for (i = (el->el_cursor.h & 0370);  +			     i < (where & 0370); i += 8) +			    term__putc('\t');	/* then tab over */ +			el->el_cursor.h = where & 0370; +		    } +		} +		/* it's usually cheaper to just write the chars, so we do. */ + +		/* NOTE THAT term_overwrite() WILL CHANGE el->el_cursor.h!!! */ +		term_overwrite(el,  +			&el->el_display[el->el_cursor.v][el->el_cursor.h],  +		        where - el->el_cursor.h); + +	    } +	} +	else {			/* del < 0 := moving backward */ +	    if ((-del > 4) && GoodStr(T_LE)) +		(void) tputs(tgoto(Str(T_LE), -del, -del), -del, term__putc); +	    else {		/* can't go directly there */ +		/* if the "cost" is greater than the "cost" from col 0 */ +		if (EL_CAN_TAB ? (-del > ((where >> 3) + (where & 07))) +		    : (-del > where)) { +		    term__putc('\r');	/* do a CR */ +		    el->el_cursor.h = 0; +		    goto mc_again;	/* and try again */ +		} +		for (i = 0; i < -del; i++) +		    term__putc('\b'); +	    } +	} +    } +    el->el_cursor.h = where;		/* now where is here */ +} /* end term_move_to_char */ + + +/* term_overwrite(): + *	Overstrike num characters + */ +protected void +term_overwrite(el, cp, n) +    EditLine *el; +    char *cp; +    int n; +{ +    if (n <= 0) +	return;			/* catch bugs */ + +    if (n > (el->el_term.t_size.h + 1)) { +#ifdef DEBUG_SCREEN +	(void) fprintf(el->el_errfile, "term_overwrite: n is riduculous: %d\r\n", n); +#endif /* DEBUG_SCREEN */ +	return; +    } + +    do { +	term__putc(*cp++); +	el->el_cursor.h++; +    } while (--n); +} /* end term_overwrite */ + + +/* term_deletechars(): + *	Delete num characters + */ +protected void +term_deletechars(el, num) +    EditLine *el; +    int     num; +{ +    if (num <= 0) +	return; + +    if (!EL_CAN_DELETE) { +#ifdef DEBUG_EDIT +	(void) fprintf(el->el_errfile, "   ERROR: cannot delete   \n"); +#endif /* DEBUG_EDIT */ +	return; +    } + +    if (num > el->el_term.t_size.h) { +#ifdef DEBUG_SCREEN +	(void) fprintf(el->el_errfile,  +		"term_deletechars: num is riduculous: %d\r\n", num); +#endif /* DEBUG_SCREEN */ +	return; +    } + +    if (GoodStr(T_DC))		/* if I have multiple delete */ +	if ((num > 1) || !GoodStr(T_dc)) {	/* if dc would be more expen. */ +	    (void) tputs(tgoto(Str(T_DC), num, num), num, term__putc); +	    return; +	} + +    if (GoodStr(T_dm))		/* if I have delete mode */ +	(void) tputs(Str(T_dm), 1, term__putc); + +    if (GoodStr(T_dc))		/* else do one at a time */ +	while (num--) +	    (void) tputs(Str(T_dc), 1, term__putc); + +    if (GoodStr(T_ed))		/* if I have delete mode */ +	(void) tputs(Str(T_ed), 1, term__putc); +} /* end term_deletechars */ + + +/* term_insertwrite(): + *	Puts terminal in insert character mode or inserts num  + *	characters in the line  + */ +protected void +term_insertwrite(el, cp, num)	 +    EditLine *el; +    char *cp; +    int num; +{ +    if (num <= 0) +	return; +    if (!EL_CAN_INSERT) { +#ifdef DEBUG_EDIT +	(void) fprintf(el->el_errfile, "   ERROR: cannot insert   \n"); +#endif /* DEBUG_EDIT */ +	return; +    } + +    if (num > el->el_term.t_size.h) { +#ifdef DEBUG_SCREEN +	(void) fprintf(el->el_errfile, "StartInsert: num is riduculous: %d\r\n", num); +#endif /* DEBUG_SCREEN */ +	return; +    } + +    if (GoodStr(T_IC))		/* if I have multiple insert */ +	if ((num > 1) || !GoodStr(T_ic)) {	/* if ic would be more expen. */ +	    (void) tputs(tgoto(Str(T_IC), num, num), num, term__putc); +	    term_overwrite(el, cp, num);	/* this updates el_cursor.h */ +	    return; +	} + +    if (GoodStr(T_im) && GoodStr(T_ei)) { /* if I have insert mode */ +	(void) tputs(Str(T_im), 1, term__putc); + +	el->el_cursor.h += num; +	do  +	    term__putc(*cp++); +	while (--num); + +	if (GoodStr(T_ip))	/* have to make num chars insert */ +	    (void) tputs(Str(T_ip), 1, term__putc); + +	(void) tputs(Str(T_ei), 1, term__putc); +	return; +    } + +    do { +	if (GoodStr(T_ic))	/* have to make num chars insert */ +	    (void) tputs(Str(T_ic), 1, term__putc);	/* insert a char */ + +	term__putc(*cp++); + +	el->el_cursor.h++; + +	if (GoodStr(T_ip))	/* have to make num chars insert */ +	    (void) tputs(Str(T_ip), 1, term__putc);/* pad the inserted char */ + +    } while (--num); +} /* end term_insertwrite */ + + +/* term_clear_EOL(): + *	clear to end of line.  There are num characters to clear  + */ +protected void +term_clear_EOL(el, num)	 +    EditLine *el; +    int     num; +{ +    int i; + +    if (EL_CAN_CEOL && GoodStr(T_ce)) +	(void) tputs(Str(T_ce), 1, term__putc); +    else { +	for (i = 0; i < num; i++) +	    term__putc(' '); +	el->el_cursor.h += num;		/* have written num spaces */ +    } +} /* end term_clear_EOL */ + + +/* term_clear_screen(): + *	Clear the screen  + */ +protected void +term_clear_screen(el) +    EditLine *el; +{				/* clear the whole screen and home */ +    if (GoodStr(T_cl)) +	/* send the clear screen code */ +	(void) tputs(Str(T_cl), Val(T_li), term__putc); +    else if (GoodStr(T_ho) && GoodStr(T_cd)) { +	(void) tputs(Str(T_ho), Val(T_li), term__putc);	/* home */ +	/* clear to bottom of screen */ +	(void) tputs(Str(T_cd), Val(T_li), term__putc); +    } +    else { +	term__putc('\r'); +	term__putc('\n'); +    } +} /* end term_clear_screen */ + + +/* term_beep(): + *	Beep the way the terminal wants us + */ +protected void +term_beep(el) +    EditLine *el; +{ +    if (GoodStr(T_vb)) +	(void) tputs(Str(T_vb), 1, term__putc);	/* visible bell */ +    else if (GoodStr(T_bl)) +	/* what termcap says we should use */ +	(void) tputs(Str(T_bl), 1, term__putc); +    else +	term__putc('\007');	/* an ASCII bell; ^G */ +} /* end term_beep */ + + +#ifdef notdef +/* term_clear_to_bottom(): + *	Clear to the bottom of the screen + */ +protected void +term_clear_to_bottom(el) +    EditLine *el; +{ +    if (GoodStr(T_cd)) +	(void) tputs(Str(T_cd), Val(T_li), term__putc); +    else if (GoodStr(T_ce)) +	(void) tputs(Str(T_ce), Val(T_li), term__putc); +} /* end term_clear_to_bottom */ +#endif + + +/* term_set(): + *	Read in the terminal capabilities from the requested terminal + */ +protected int +term_set(el, term) +    EditLine *el; +    char *term; +{ +    int i; +    char    buf[TC_BUFSIZE]; +    char   *area; +    struct termcapstr *t; +    sigset_t oset, nset; +    int     lins, cols; + +    (void) sigemptyset(&nset); +    (void) sigaddset(&nset, SIGWINCH); +    (void) sigprocmask(SIG_BLOCK, &nset, &oset); + +    area = buf; + + +    if (term == NULL) +	term = getenv("TERM"); + +    if (!term || !term[0]) +	term = "dumb"; + +    memset(el->el_term.t_cap, 0, TC_BUFSIZE); + +    i = tgetent(el->el_term.t_cap, term); + +    if (i <= 0) { +	if (i == -1)  +	    (void) fprintf(el->el_errfile, "Cannot open /etc/termcap.\n"); +	else if (i == 0)  +	    (void) fprintf(el->el_errfile,  +			   "No entry for terminal type \"%s\"\n", term); +	(void) fprintf(el->el_errfile, "using dumb terminal settings.\n"); +	Val(T_co) = 80;		/* do a dumb terminal */ +	Val(T_pt) = Val(T_km) = Val(T_li) = 0; +	Val(T_xt) = Val(T_MT); +	for (t = tstr; t->name != NULL; t++) +	    term_alloc(el, t, NULL); +    } +    else { +	/* Can we tab */ +	Val(T_pt) = tgetflag("pt"); +	Val(T_xt) = tgetflag("xt"); +	/* do we have a meta? */ +	Val(T_km) = tgetflag("km"); +	Val(T_MT) = tgetflag("MT"); +	/* Get the size */ +	Val(T_co) = tgetnum("co"); +	Val(T_li) = tgetnum("li"); +	for (t = tstr; t->name != NULL; t++) +	    term_alloc(el, t, tgetstr(t->name, &area)); +    } + +    if (Val(T_co) < 2) +	Val(T_co) = 80;		/* just in case */ +    if (Val(T_li) < 1) +	Val(T_li) = 24; + +    el->el_term.t_size.v = Val(T_co); +    el->el_term.t_size.h = Val(T_li); + +    term_setflags(el); + +    (void) term_get_size(el, &lins, &cols);/* get the correct window size */ +    term_change_size(el, lins, cols); +    (void) sigprocmask(SIG_SETMASK, &oset, NULL); +    term_bind_arrow(el); +    return 0; +} /* end term_set */ + + +/* term_get_size(): + *	Return the new window size in lines and cols, and + *	true if the size was changed.  + */ +protected int +term_get_size(el, lins, cols) +    EditLine *el; +    int    *lins, *cols; +{ + +    *cols = Val(T_co); +    *lins = Val(T_li); + +#ifdef TIOCGWINSZ +    { +	struct winsize ws; +	if (ioctl(el->el_infd, TIOCGWINSZ, (ioctl_t) &ws) != -1) { +	    if (ws.ws_col) +		*cols = ws.ws_col; +	    if (ws.ws_row) +		*lins = ws.ws_row; +	} +    } +#endif +#ifdef TIOCGSIZE +    { +	struct ttysize ts; +	if (ioctl(el->el_infd, TIOCGSIZE, (ioctl_t) &ts) != -1) { +	    if (ts.ts_cols) +		*cols = ts.ts_cols; +	    if (ts.ts_lines) +		*lins = ts.ts_lines; +	} +    } +#endif +    return (Val(T_co) != *cols || Val(T_li) != *lins); +} /* end term_get_size */ + + +/* term_change_size(): + *	Change the size of the terminal + */ +protected void +term_change_size(el, lins, cols) +    EditLine *el; +    int     lins, cols; +{ +    /* +     * Just in case +     */ +    Val(T_co) = (cols < 2) ? 80 : cols; +    Val(T_li) = (lins < 1) ? 24 : lins; + +    term_rebuffer_display(el);		/* re-make display buffers */ +    re_clear_display(el); +} /* end term_change_size */ + + +/* term_init_arrow(): + *	Initialize the arrow key bindings from termcap + */ +private void +term_init_arrow(el) +    EditLine *el; +{ +    fkey_t *arrow = el->el_term.t_fkey; + +    arrow[A_K_DN].name    = "down"; +    arrow[A_K_DN].key	  = T_kd; +    arrow[A_K_DN].fun.cmd = ED_NEXT_HISTORY; +    arrow[A_K_DN].type    = XK_CMD; + +    arrow[A_K_UP].name    = "up"; +    arrow[A_K_UP].key	  = T_ku; +    arrow[A_K_UP].fun.cmd = ED_PREV_HISTORY; +    arrow[A_K_UP].type    = XK_CMD; + +    arrow[A_K_LT].name    = "left"; +    arrow[A_K_LT].key	  = T_kl; +    arrow[A_K_LT].fun.cmd = ED_PREV_CHAR; +    arrow[A_K_LT].type    = XK_CMD; + +    arrow[A_K_RT].name    = "right"; +    arrow[A_K_RT].key	  = T_kr; +    arrow[A_K_RT].fun.cmd = ED_NEXT_CHAR; +    arrow[A_K_RT].type    = XK_CMD; + +} + + +/* term_reset_arrow(): + *	Reset arrow key bindings + */ +private void +term_reset_arrow(el)  +    EditLine *el; +{ +    fkey_t *arrow = el->el_term.t_fkey; +    static char strA[] = {033, '[', 'A', '\0'}; +    static char strB[] = {033, '[', 'B', '\0'}; +    static char strC[] = {033, '[', 'C', '\0'}; +    static char strD[] = {033, '[', 'D', '\0'}; +    static char stOA[] = {033, 'O', 'A', '\0'}; +    static char stOB[] = {033, 'O', 'B', '\0'}; +    static char stOC[] = {033, 'O', 'C', '\0'}; +    static char stOD[] = {033, 'O', 'D', '\0'}; + +    key_add(el, strA, &arrow[A_K_UP].fun, arrow[A_K_UP].type); +    key_add(el, strB, &arrow[A_K_DN].fun, arrow[A_K_DN].type); +    key_add(el, strC, &arrow[A_K_RT].fun, arrow[A_K_RT].type); +    key_add(el, strD, &arrow[A_K_LT].fun, arrow[A_K_LT].type); +    key_add(el, stOA, &arrow[A_K_UP].fun, arrow[A_K_UP].type); +    key_add(el, stOB, &arrow[A_K_DN].fun, arrow[A_K_DN].type); +    key_add(el, stOC, &arrow[A_K_RT].fun, arrow[A_K_RT].type); +    key_add(el, stOD, &arrow[A_K_LT].fun, arrow[A_K_LT].type); + +    if (el->el_map.type == MAP_VI) { +	key_add(el, &strA[1], &arrow[A_K_UP].fun, arrow[A_K_UP].type); +	key_add(el, &strB[1], &arrow[A_K_DN].fun, arrow[A_K_DN].type); +	key_add(el, &strC[1], &arrow[A_K_RT].fun, arrow[A_K_RT].type); +	key_add(el, &strD[1], &arrow[A_K_LT].fun, arrow[A_K_LT].type); +	key_add(el, &stOA[1], &arrow[A_K_UP].fun, arrow[A_K_UP].type); +	key_add(el, &stOB[1], &arrow[A_K_DN].fun, arrow[A_K_DN].type); +	key_add(el, &stOC[1], &arrow[A_K_RT].fun, arrow[A_K_RT].type); +	key_add(el, &stOD[1], &arrow[A_K_LT].fun, arrow[A_K_LT].type); +    } +} + + +/* term_set_arrow(): + *	Set an arrow key binding + */ +protected int +term_set_arrow(el, name, fun, type) +    EditLine *el; +    char *name; +    key_value_t *fun; +    int type; +{ +    fkey_t *arrow = el->el_term.t_fkey; +    int i; + +    for (i = 0; i < A_K_NKEYS; i++) +	if (strcmp(name, arrow[i].name) == 0) { +	    arrow[i].fun  = *fun; +	    arrow[i].type = type; +	    return 0; +	} +    return -1; +} + + +/* term_clear_arrow(): + *	Clear an arrow key binding + */ +protected int +term_clear_arrow(el, name) +    EditLine *el; +    char *name; +{ +    fkey_t *arrow = el->el_term.t_fkey; +    int i; + +    for (i = 0; i < A_K_NKEYS; i++) +	if (strcmp(name, arrow[i].name) == 0) { +	    arrow[i].type = XK_NOD; +	    return 0; +	} +    return -1; +} + + +/* term_print_arrow(): + *	Print the arrow key bindings + */ +protected void +term_print_arrow(el, name) +    EditLine *el; +    char *name; +{ +    int i; +    fkey_t *arrow = el->el_term.t_fkey; + +    for (i = 0; i < A_K_NKEYS; i++) +	if (*name == '\0' || strcmp(name, arrow[i].name) == 0) +	    if (arrow[i].type != XK_NOD) +		key_kprint(el, arrow[i].name, &arrow[i].fun, arrow[i].type); +} + + +/* term_bind_arrow(): + *	Bind the arrow keys + */ +protected void +term_bind_arrow(el) +    EditLine *el; +{ +    el_action_t *map, *dmap; +    int     i, j; +    char   *p; +    fkey_t *arrow = el->el_term.t_fkey; + +    /* Check if the components needed are initialized */ +    if (el->el_term.t_buf == NULL || el->el_map.key == NULL) +	return; + +    map  = el->el_map.type == MAP_VI ? el->el_map.alt : el->el_map.key; +    dmap = el->el_map.type == MAP_VI ? el->el_map.vic : el->el_map.emacs; + +    term_reset_arrow(el); + +    for (i = 0; i < 4; i++) { +	p = el->el_term.t_str[arrow[i].key]; +	if (p && *p) { +	    j = (unsigned char) *p; +	    /* +	     * Assign the arrow keys only if: +	     * +	     * 1. They are multi-character arrow keys and the user  +	     *    has not re-assigned the leading character, or  +	     *    has re-assigned the leading character to be +	     *	  ED_SEQUENCE_LEAD_IN +	     * 2. They are single arrow keys pointing to an unassigned key. +	     */ +	    if (arrow[i].type == XK_NOD) +		key_clear(el, map, p); +	    else { +		if (p[1] && (dmap[j] == map[j] ||  +			     map[j] == ED_SEQUENCE_LEAD_IN)) { +		    key_add(el, p, &arrow[i].fun, arrow[i].type); +		    map[j] = ED_SEQUENCE_LEAD_IN; +		} +		else if (map[j] == ED_UNASSIGNED) { +		    key_clear(el, map, p); +		    if (arrow[i].type == XK_CMD) +			map[j] = arrow[i].fun.cmd; +		    else +			key_add(el, p, &arrow[i].fun, arrow[i].type); +		} +	    } +	} +    } +} + + +/* term__putc(): + *	Add a character + */ +protected void +term__putc(c) +    int c; +{ +    (void) fputc(c, term_outfile); +} /* end term__putc */ + + +/* term__flush(): + *	Flush output + */ +protected void +term__flush() +{ +    (void) fflush(term_outfile); +} /* end term__flush */ + + +/* term_telltc(): + *	Print the current termcap characteristics + */ +protected int +/*ARGSUSED*/ +term_telltc(el, argc, argv) +    EditLine *el; +    int argc; +    char **argv; +{ +    struct termcapstr *t; +    char **ts; +    char upbuf[EL_BUFSIZ]; + +    (void) fprintf(el->el_outfile, "\n\tYour terminal has the\n"); +    (void) fprintf(el->el_outfile, "\tfollowing characteristics:\n\n"); +    (void) fprintf(el->el_outfile, "\tIt has %d columns and %d lines\n", +	    Val(T_co), Val(T_li)); +    (void) fprintf(el->el_outfile,  +		   "\tIt has %s meta key\n", EL_HAS_META ? "a" : "no"); +    (void) fprintf(el->el_outfile,  +		   "\tIt can%suse tabs\n", EL_CAN_TAB ? " " : "not "); +#ifdef notyet +    (void) fprintf(el->el_outfile, "\tIt %s automatic margins\n",  +		   (T_Margin&MARGIN_AUTO)? "has": "does not have"); +    if (T_Margin & MARGIN_AUTO) +	(void) fprintf(el->el_outfile, "\tIt %s magic margins\n",  +			(T_Margin&MARGIN_MAGIC)?"has":"does not have"); +#endif + +    for (t = tstr, ts = el->el_term.t_str; t->name != NULL; t++, ts++) +	(void) fprintf(el->el_outfile, "\t%25s (%s) == %s\n", t->long_name,  +		       t->name, *ts && **ts ?  +			key__decode_str(*ts, upbuf, "") : "(empty)"); +    (void) fputc('\n', el->el_outfile); +    return 0; +} + + +/* term_settc(): + *	Change the current terminal characteristics + */ +protected int +/*ARGSUSED*/ +term_settc(el, argc, argv) +    EditLine *el; +    int argc; +    char **argv; +{ +    struct termcapstr *ts; +    struct termcapval *tv; +    char   *what, *how; + +    if (argv == NULL || argv[1] == NULL || argv[2] == NULL) +	return -1; + +    what = argv[1]; +    how = argv[2]; + +    /* +     * Do the strings first +     */ +    for (ts = tstr; ts->name != NULL; ts++) +	if (strcmp(ts->name, what) == 0) +	    break; + +    if (ts->name != NULL) { +	term_alloc(el, ts, how); +	term_setflags(el); +	return 0; +    } + +    /* +     * Do the numeric ones second +     */ +    for (tv = tval; tv->name != NULL; tv++) +	if (strcmp(tv->name, what) == 0) +	    break; + +    if (tv->name != NULL) { +	if (tv == &tval[T_pt] || tv == &tval[T_km]  +#ifdef notyet +	    || tv == &tval[T_am] || tv == &tval[T_xn] +#endif +	    ) { +	    if (strcmp(how, "yes") == 0) +		el->el_term.t_val[tv - tval] = 1; +	    else if (strcmp(how, "no") == 0) +		el->el_term.t_val[tv - tval] = 0; +	    else { +		(void) fprintf(el->el_errfile, "settc: Bad value `%s'.\n", how); +		return -1; +	    } +	    term_setflags(el); +	    term_change_size(el, Val(T_li), Val(T_co)); +	    return 0; +	} +	else { +	    el->el_term.t_val[tv - tval] = atoi(how); +	    el->el_term.t_size.v = Val(T_co); +	    el->el_term.t_size.h = Val(T_li); +	    if (tv == &tval[T_co] || tv == &tval[T_li]) +		term_change_size(el, Val(T_li), Val(T_co)); +	    return 0; +	} +    } +    return -1; +} + + +/* term_echotc(): + *	Print the termcap string out with variable substitution + */ +protected int +/*ARGSUSED*/ +term_echotc(el, argc, argv) +    EditLine *el; +    int argc; +    char **argv; +{ +    char   *cap, *scap; +    int     arg_need, arg_cols, arg_rows; +    int     verbose = 0, silent = 0; +    char   *area; +    static char *fmts = "%s\n", *fmtd = "%d\n"; +    struct termcapstr *t; +    char    buf[TC_BUFSIZE]; + +    area = buf; + +    if (argv == NULL || argv[1] == NULL) +	return -1; +    argv++; + +    if (argv[0][0] == '-') { +	switch (argv[0][1]) { +	case 'v': +	    verbose = 1; +	    break; +	case 's': +	    silent = 1; +	    break; +	default: +	    /* stderror(ERR_NAME | ERR_TCUSAGE); */ +	    break; +	} +	argv++; +    } +    if (!*argv || *argv[0] == '\0') +	return 0; +    if (strcmp(*argv, "tabs") == 0) { +	(void) fprintf(el->el_outfile, fmts, EL_CAN_TAB ? "yes" : "no"); +	return 0; +    } +    else if (strcmp(*argv, "meta") == 0) { +	(void) fprintf(el->el_outfile, fmts, Val(T_km) ? "yes" : "no"); +	return 0; +    } +#ifdef notyet +    else if (strcmp(*argv, "xn") == 0) { +	(void) fprintf(el->el_outfile, fmts, T_Margin & MARGIN_MAGIC ?  +			"yes" : "no"); +	return 0; +    } +    else if (strcmp(*argv, "am") == 0) { +	(void) fprintf(el->el_outfile, fmts, T_Margin & MARGIN_AUTO ?  +			"yes" : "no"); +	return 0; +    } +#endif +    else if (strcmp(*argv, "baud") == 0) { +	int     i; + +	for (i = 0; baud_rate[i].b_name != NULL; i++) +	    if (el->el_tty.t_speed == baud_rate[i].b_rate) { +		(void) fprintf(el->el_outfile, fmts, baud_rate[i].b_name); +		return 0; +	    } +	(void) fprintf(el->el_outfile, fmtd, 0); +	return 0; +    } +    else if (strcmp(*argv, "rows") == 0 || strcmp(*argv, "lines") == 0) { +	(void) fprintf(el->el_outfile, fmtd, Val(T_li)); +	return 0; +    } +    else if (strcmp(*argv, "cols") == 0) { +	(void) fprintf(el->el_outfile, fmtd, Val(T_co)); +	return 0; +    } + +    /*  +     * Try to use our local definition first +     */ +    scap = NULL; +    for (t = tstr; t->name != NULL; t++) +	if (strcmp(t->name, *argv) == 0) { +	    scap = el->el_term.t_str[t - tstr]; +	    break; +	} +    if (t->name == NULL) +	scap = tgetstr(*argv, &area); +    if (!scap || scap[0] == '\0') { +	if (!silent) +	    (void) fprintf(el->el_errfile,  +		"echotc: Termcap parameter `%s' not found.\n", *argv); +	return -1; +    } + +    /* +     * Count home many values we need for this capability. +     */ +    for (cap = scap, arg_need = 0; *cap; cap++) +	if (*cap == '%') +	    switch (*++cap) { +	    case 'd': +	    case '2': +	    case '3': +	    case '.': +	    case '+': +		arg_need++; +		break; +	    case '%': +	    case '>': +	    case 'i': +	    case 'r': +	    case 'n': +	    case 'B': +	    case 'D': +		break; +	    default: +		/* +		 * hpux has lot's of them... +		 */ +		if (verbose) +		    (void) fprintf(el->el_errfile,  +			"echotc: Warning: unknown termcap %% `%c'.\n", *cap); +		/* This is bad, but I won't complain */ +		break; +	    } + +    switch (arg_need) { +    case 0: +	argv++; +	if (*argv && *argv[0]) { +	    if (!silent) +		(void) fprintf(el->el_errfile,  +		    "echotc: Warning: Extra argument `%s'.\n", *argv); +	    return -1; +	} +	(void) tputs(scap, 1, term__putc); +	break; +    case 1: +	argv++; +	if (!*argv || *argv[0] == '\0') { +	    if (!silent) +		(void) fprintf(el->el_errfile,  +		    "echotc: Warning: Missing argument.\n"); +	    return -1; +	} +	arg_cols = 0; +	arg_rows = atoi(*argv); +	argv++; +	if (*argv && *argv[0]) { +	    if (!silent) +		(void) fprintf(el->el_errfile,  +		    "echotc: Warning: Extra argument `%s'.\n", *argv); +	    return -1; +	} +	(void) tputs(tgoto(scap, arg_cols, arg_rows), 1, term__putc); +	break; +    default: +	/* This is wrong, but I will ignore it... */ +	if (verbose) +	    (void) fprintf(el->el_errfile,  +		"echotc: Warning: Too many required arguments (%d).\n",  +		arg_need); +	/*FALLTHROUGH*/ +    case 2: +	argv++; +	if (!*argv || *argv[0] == '\0') { +	    if (!silent) +		(void) fprintf(el->el_errfile,  +		    "echotc: Warning: Missing argument.\n"); +	    return -1; +	} +	arg_cols = atoi(*argv); +	argv++; +	if (!*argv || *argv[0] == '\0') { +	    if (!silent) +		(void) fprintf(el->el_errfile,  +		    "echotc: Warning: Missing argument.\n"); +	    return -1; +	} +	arg_rows = atoi(*argv); +	argv++; +	if (*argv && *argv[0]) { +	    if (!silent) +		(void) fprintf(el->el_errfile,  +		    "echotc: Warning: Extra argument `%s'.\n", *argv); +	    return -1; +	} +	(void) tputs(tgoto(scap, arg_cols, arg_rows), arg_rows, term__putc); +	break; +    } +    return 0; +} diff --git a/lib/libedit/termcap.h b/lib/libedit/termcap.h new file mode 100644 index 000000000000..4fd2cab0ec02 --- /dev/null +++ b/lib/libedit/termcap.h @@ -0,0 +1,52 @@ +/*- + * Copyright (c) 1992, 1993 + *	The Regents of the University of California.  All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Christos Zoulas of Cornell University. + * + * 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. + * + *	@(#)termcap.h	8.1 (Berkeley) 6/4/93 + */ + +/* + * termcap.h: I cannot find those in any include files... + */ +#ifndef _h_termcap +#define _h_termcap + +int   tgetent	__P((char *, char *)); +char *tgetstr	__P((char *, char **)); +int   tgetflag	__P((char *)); +int   tgetnum	__P((char *)); +char *tgoto	__P((char *, int, int)); +char *tputs	__P((char *, int, void (*)(int))); + +#endif /* _h_termcap */ diff --git a/lib/libkvm/Makefile b/lib/libkvm/Makefile new file mode 100644 index 000000000000..0a5ca388be95 --- /dev/null +++ b/lib/libkvm/Makefile @@ -0,0 +1,14 @@ +#	@(#)Makefile	8.3 (Berkeley) 5/4/95 + +LIB=	kvm +CFLAGS+=-DLIBC_SCCS -I/sys +SRCS=	kvm.c kvm_${MACHINE}.c kvm_file.c kvm_getloadavg.c kvm_proc.c + +MAN3=	kvm.0 kvm_geterr.0 kvm_getfiles.0 kvm_getloadavg.0 kvm_getprocs.0 \ +	kvm_nlist.0 kvm_open.0 kvm_read.0 + +MLINKS+=kvm_getprocs.3 kvm_getargv.3 kvm_getprocs.3 kvm_getenvv.3 +MLINKS+=kvm_open.3 kvm_openfiles.3 kvm_open.3 kvm_close.3 +MLINKS+=kvm_read.3 kvm_write.3 + +.include <bsd.lib.mk> diff --git a/lib/libkvm/kvm_file.c b/lib/libkvm/kvm_file.c new file mode 100644 index 000000000000..6786209f52d0 --- /dev/null +++ b/lib/libkvm/kvm_file.c @@ -0,0 +1,190 @@ +/*- + * Copyright (c) 1989, 1992, 1993 + *	The 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. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static char sccsid[] = "@(#)kvm_file.c	8.2 (Berkeley) 8/20/94"; +#endif /* LIBC_SCCS and not lint */ + +/* + * File list interface for kvm.  pstat, fstat and netstat are  + * users of this code, so we've factored it out into a separate module. + * Thus, we keep this grunge out of the other kvm applications (i.e., + * most other applications are interested only in open/close/read/nlist). + */ + +#include <sys/param.h> +#include <sys/user.h> +#include <sys/proc.h> +#include <sys/exec.h> +#define KERNEL +#include <sys/file.h> +#undef KERNEL +#include <sys/stat.h> +#include <sys/ioctl.h> +#include <sys/tty.h> +#include <nlist.h> +#include <kvm.h> + +#include <vm/vm.h> +#include <vm/vm_param.h> +#include <vm/swap_pager.h> + +#include <sys/sysctl.h> + +#include <limits.h> +#include <ndbm.h> +#include <paths.h> + +#include "kvm_private.h" + +#define KREAD(kd, addr, obj) \ +	(kvm_read(kd, addr, obj, sizeof(*obj)) != sizeof(*obj)) + +/* + * Get file structures. + */ +static +kvm_deadfiles(kd, op, arg, filehead_o, nfiles) +	kvm_t *kd; +	int op, arg, nfiles; +	long filehead_o; +{ +	int buflen = kd->arglen, needed = buflen, error, n = 0; +	struct file *fp, file; +	struct filelist filehead; +	register char *where = kd->argspc; +	char *start = where; + +	/* +	 * first copyout filehead +	 */ +	if (buflen > sizeof (filehead)) { +		if (KREAD(kd, filehead_o, &filehead)) { +			_kvm_err(kd, kd->program, "can't read filehead"); +			return (0); +		} +		buflen -= sizeof (filehead); +		where += sizeof (filehead); +		*(struct filelist *)kd->argspc = filehead; +	} +	/* +	 * followed by an array of file structures +	 */ +	for (fp = filehead.lh_first; fp != 0; fp = fp->f_list.le_next) { +		if (buflen > sizeof (struct file)) { +			if (KREAD(kd, (long)fp, ((struct file *)where))) { +				_kvm_err(kd, kd->program, "can't read kfp"); +				return (0); +			} +			buflen -= sizeof (struct file); +			fp = (struct file *)where; +			where += sizeof (struct file); +			n++; +		} +	} +	if (n != nfiles) { +		_kvm_err(kd, kd->program, "inconsistant nfiles"); +		return (0); +	} +	return (nfiles); +} + +char * +kvm_getfiles(kd, op, arg, cnt) +	kvm_t *kd; +	int op, arg; +	int *cnt; +{ +	int mib[2], size, st, nfiles; +	struct file *fp, *fplim; +	struct filelist filehead; + +	if (ISALIVE(kd)) { +		size = 0; +		mib[0] = CTL_KERN; +		mib[1] = KERN_FILE; +		st = sysctl(mib, 2, NULL, &size, NULL, 0); +		if (st == -1) { +			_kvm_syserr(kd, kd->program, "kvm_getprocs"); +			return (0); +		} +		if (kd->argspc == 0) +			kd->argspc = (char *)_kvm_malloc(kd, size); +		else if (kd->arglen < size) +			kd->argspc = (char *)_kvm_realloc(kd, kd->argspc, size); +		if (kd->argspc == 0) +			return (0); +		kd->arglen = size; +		st = sysctl(mib, 2, kd->argspc, &size, NULL, 0); +		if (st == -1 || size < sizeof(filehead)) { +			_kvm_syserr(kd, kd->program, "kvm_getfiles"); +			return (0); +		} +		filehead = *(struct filelist *)kd->argspc; +		fp = (struct file *)(kd->argspc + sizeof (filehead)); +		fplim = (struct file *)(kd->argspc + size); +		for (nfiles = 0; filehead.lh_first && (fp < fplim); nfiles++, fp++) +			filehead.lh_first = fp->f_list.le_next; +	} else { +		struct nlist nl[3], *p; + +		nl[0].n_name = "_filehead"; +		nl[1].n_name = "_nfiles"; +		nl[2].n_name = 0; + +		if (kvm_nlist(kd, nl) != 0) { +			for (p = nl; p->n_type != 0; ++p) +				; +			_kvm_err(kd, kd->program, +				 "%s: no such symbol", p->n_name); +			return (0); +		} +		if (KREAD(kd, nl[0].n_value, &nfiles)) { +			_kvm_err(kd, kd->program, "can't read nfiles"); +			return (0); +		} +		size = sizeof(filehead) + (nfiles + 10) * sizeof(struct file); +		if (kd->argspc == 0) +			kd->argspc = (char *)_kvm_malloc(kd, size); +		else if (kd->arglen < size) +			kd->argspc = (char *)_kvm_realloc(kd, kd->argspc, size); +		if (kd->argspc == 0) +			return (0); +		kd->arglen = size; +		nfiles = kvm_deadfiles(kd, op, arg, nl[1].n_value, nfiles); +		if (nfiles == 0) +			return (0); +	} +	*cnt = nfiles; +	return (kd->argspc); +} diff --git a/lib/libkvm/kvm_proc.c b/lib/libkvm/kvm_proc.c new file mode 100644 index 000000000000..7a36ef67f4a0 --- /dev/null +++ b/lib/libkvm/kvm_proc.c @@ -0,0 +1,705 @@ +/*- + * Copyright (c) 1989, 1992, 1993 + *	The Regents of the University of California.  All rights reserved. + * + * This code is derived from software developed by the Computer Systems + * Engineering group at Lawrence Berkeley Laboratory under DARPA contract + * BG 91-66 and contributed to Berkeley. + * + * 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. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static char sccsid[] = "@(#)kvm_proc.c	8.4 (Berkeley) 8/20/94"; +#endif /* LIBC_SCCS and not lint */ + +/* + * Proc traversal interface for kvm.  ps and w are (probably) the exclusive + * users of this code, so we've factored it out into a separate module. + * Thus, we keep this grunge out of the other kvm applications (i.e., + * most other applications are interested only in open/close/read/nlist). + */ + +#include <sys/param.h> +#include <sys/user.h> +#include <sys/proc.h> +#include <sys/exec.h> +#include <sys/stat.h> +#include <sys/ioctl.h> +#include <sys/tty.h> +#include <unistd.h> +#include <nlist.h> +#include <kvm.h> + +#include <vm/vm.h> +#include <vm/vm_param.h> +#include <vm/swap_pager.h> + +#include <sys/sysctl.h> + +#include <limits.h> +#include <db.h> +#include <paths.h> + +#include "kvm_private.h" + +static char * +kvm_readswap(kd, p, va, cnt) +	kvm_t *kd; +	const struct proc *p; +	u_long va; +	u_long *cnt; +{ +	register int ix; +	register u_long addr, head; +	register u_long offset, pagestart, sbstart, pgoff; +	register off_t seekpoint; +	struct vm_map_entry vme; +	struct vm_object vmo; +	struct pager_struct pager; +	struct swpager swap; +	struct swblock swb; +	static char page[NBPG]; + +	head = (u_long)&p->p_vmspace->vm_map.header; +	/* +	 * Look through the address map for the memory object +	 * that corresponds to the given virtual address. +	 * The header just has the entire valid range. +	 */ +	addr = head; +	while (1) { +		if (kvm_read(kd, addr, (char *)&vme, sizeof(vme)) !=  +		    sizeof(vme)) +			return (0); + +		if (va >= vme.start && va <= vme.end &&  +		    vme.object.vm_object != 0) +			break; + +		addr = (u_long)vme.next; +		if (addr == 0 || addr == head) +			return (0); +	} +	/* +	 * We found the right object -- follow shadow links. +	 */ +	offset = va - vme.start + vme.offset; +	addr = (u_long)vme.object.vm_object; +	while (1) { +		if (kvm_read(kd, addr, (char *)&vmo, sizeof(vmo)) !=  +		    sizeof(vmo)) +			return (0); +		addr = (u_long)vmo.shadow; +		if (addr == 0) +			break; +		offset += vmo.shadow_offset; +	} +	if (vmo.pager == 0) +		return (0); + +	offset += vmo.paging_offset; +	/* +	 * Read in the pager info and make sure it's a swap device. +	 */ +	addr = (u_long)vmo.pager; +	if (kvm_read(kd, addr, (char *)&pager, sizeof(pager)) != sizeof(pager) +	    || pager.pg_type != PG_SWAP) +		return (0); + +	/* +	 * Read in the swap_pager private data, and compute the +	 * swap offset. +	 */ +	addr = (u_long)pager.pg_data; +	if (kvm_read(kd, addr, (char *)&swap, sizeof(swap)) != sizeof(swap)) +		return (0); +	ix = offset / dbtob(swap.sw_bsize); +	if (swap.sw_blocks == 0 || ix >= swap.sw_nblocks) +		return (0); + +	addr = (u_long)&swap.sw_blocks[ix]; +	if (kvm_read(kd, addr, (char *)&swb, sizeof(swb)) != sizeof(swb)) +		return (0); + +	sbstart = (offset / dbtob(swap.sw_bsize)) * dbtob(swap.sw_bsize); +	sbstart /= NBPG; +	pagestart = offset / NBPG; +	pgoff = pagestart - sbstart; + +	if (swb.swb_block == 0 || (swb.swb_mask & (1 << pgoff)) == 0) +		return (0); + +	seekpoint = dbtob(swb.swb_block) + ctob(pgoff); +	errno = 0; +	if (lseek(kd->swfd, seekpoint, 0) == -1 && errno != 0) +		return (0); +	if (read(kd->swfd, page, sizeof(page)) != sizeof(page)) +		return (0); + +	offset %= NBPG; +	*cnt = NBPG - offset; +	return (&page[offset]); +} + +#define KREAD(kd, addr, obj) \ +	(kvm_read(kd, addr, (char *)(obj), sizeof(*obj)) != sizeof(*obj)) + +/* + * Read proc's from memory file into buffer bp, which has space to hold + * at most maxcnt procs. + */ +static int +kvm_proclist(kd, what, arg, p, bp, maxcnt) +	kvm_t *kd; +	int what, arg; +	struct proc *p; +	struct kinfo_proc *bp; +	int maxcnt; +{ +	register int cnt = 0; +	struct eproc eproc; +	struct pgrp pgrp; +	struct session sess; +	struct tty tty; +	struct proc proc; + +	for (; cnt < maxcnt && p != 0; p = proc.p_list.le_next) { +		if (KREAD(kd, (u_long)p, &proc)) { +			_kvm_err(kd, kd->program, "can't read proc at %x", p); +			return (-1); +		} +		if (KREAD(kd, (u_long)proc.p_cred, &eproc.e_pcred) == 0) +			KREAD(kd, (u_long)eproc.e_pcred.pc_ucred, +			      &eproc.e_ucred); + +		switch(what) { +			 +		case KERN_PROC_PID: +			if (proc.p_pid != (pid_t)arg) +				continue; +			break; + +		case KERN_PROC_UID: +			if (eproc.e_ucred.cr_uid != (uid_t)arg) +				continue; +			break; + +		case KERN_PROC_RUID: +			if (eproc.e_pcred.p_ruid != (uid_t)arg) +				continue; +			break; +		} +		/* +		 * We're going to add another proc to the set.  If this +		 * will overflow the buffer, assume the reason is because +		 * nprocs (or the proc list) is corrupt and declare an error. +		 */ +		if (cnt >= maxcnt) { +			_kvm_err(kd, kd->program, "nprocs corrupt"); +			return (-1); +		} +		/* +		 * gather eproc +		 */ +		eproc.e_paddr = p; +		if (KREAD(kd, (u_long)proc.p_pgrp, &pgrp)) { +			_kvm_err(kd, kd->program, "can't read pgrp at %x", +				 proc.p_pgrp); +			return (-1); +		} +		eproc.e_sess = pgrp.pg_session; +		eproc.e_pgid = pgrp.pg_id; +		eproc.e_jobc = pgrp.pg_jobc; +		if (KREAD(kd, (u_long)pgrp.pg_session, &sess)) { +			_kvm_err(kd, kd->program, "can't read session at %x",  +				pgrp.pg_session); +			return (-1); +		} +		if ((proc.p_flag & P_CONTROLT) && sess.s_ttyp != NULL) { +			if (KREAD(kd, (u_long)sess.s_ttyp, &tty)) { +				_kvm_err(kd, kd->program, +					 "can't read tty at %x", sess.s_ttyp); +				return (-1); +			} +			eproc.e_tdev = tty.t_dev; +			eproc.e_tsess = tty.t_session; +			if (tty.t_pgrp != NULL) { +				if (KREAD(kd, (u_long)tty.t_pgrp, &pgrp)) { +					_kvm_err(kd, kd->program, +						 "can't read tpgrp at &x",  +						tty.t_pgrp); +					return (-1); +				} +				eproc.e_tpgid = pgrp.pg_id; +			} else +				eproc.e_tpgid = -1; +		} else +			eproc.e_tdev = NODEV; +		eproc.e_flag = sess.s_ttyvp ? EPROC_CTTY : 0; +		if (sess.s_leader == p) +			eproc.e_flag |= EPROC_SLEADER; +		if (proc.p_wmesg) +			(void)kvm_read(kd, (u_long)proc.p_wmesg,  +			    eproc.e_wmesg, WMESGLEN); + +#ifdef sparc +		(void)kvm_read(kd, (u_long)&proc.p_vmspace->vm_rssize, +		    (char *)&eproc.e_vm.vm_rssize, +		    sizeof(eproc.e_vm.vm_rssize)); +		(void)kvm_read(kd, (u_long)&proc.p_vmspace->vm_tsize, +		    (char *)&eproc.e_vm.vm_tsize, +		    3 * sizeof(eproc.e_vm.vm_rssize));	/* XXX */ +#else +		(void)kvm_read(kd, (u_long)proc.p_vmspace, +		    (char *)&eproc.e_vm, sizeof(eproc.e_vm)); +#endif +		eproc.e_xsize = eproc.e_xrssize = 0; +		eproc.e_xccount = eproc.e_xswrss = 0; + +		switch (what) { + +		case KERN_PROC_PGRP: +			if (eproc.e_pgid != (pid_t)arg) +				continue; +			break; + +		case KERN_PROC_TTY: +			if ((proc.p_flag & P_CONTROLT) == 0 ||  +			     eproc.e_tdev != (dev_t)arg) +				continue; +			break; +		} +		bcopy(&proc, &bp->kp_proc, sizeof(proc)); +		bcopy(&eproc, &bp->kp_eproc, sizeof(eproc)); +		++bp; +		++cnt; +	} +	return (cnt); +} + +/* + * Build proc info array by reading in proc list from a crash dump. + * Return number of procs read.  maxcnt is the max we will read. + */ +static int +kvm_deadprocs(kd, what, arg, a_allproc, a_zombproc, maxcnt) +	kvm_t *kd; +	int what, arg; +	u_long a_allproc; +	u_long a_zombproc; +	int maxcnt; +{ +	register struct kinfo_proc *bp = kd->procbase; +	register int acnt, zcnt; +	struct proc *p; + +	if (KREAD(kd, a_allproc, &p)) { +		_kvm_err(kd, kd->program, "cannot read allproc"); +		return (-1); +	} +	acnt = kvm_proclist(kd, what, arg, p, bp, maxcnt); +	if (acnt < 0) +		return (acnt); + +	if (KREAD(kd, a_zombproc, &p)) { +		_kvm_err(kd, kd->program, "cannot read zombproc"); +		return (-1); +	} +	zcnt = kvm_proclist(kd, what, arg, p, bp + acnt, maxcnt - acnt); +	if (zcnt < 0) +		zcnt = 0; + +	return (acnt + zcnt); +} + +struct kinfo_proc * +kvm_getprocs(kd, op, arg, cnt) +	kvm_t *kd; +	int op, arg; +	int *cnt; +{ +	int mib[4], size, st, nprocs; + +	if (kd->procbase != 0) { +		free((void *)kd->procbase); +		/*  +		 * Clear this pointer in case this call fails.  Otherwise, +		 * kvm_close() will free it again. +		 */ +		kd->procbase = 0; +	} +	if (ISALIVE(kd)) { +		size = 0; +		mib[0] = CTL_KERN; +		mib[1] = KERN_PROC; +		mib[2] = op; +		mib[3] = arg; +		st = sysctl(mib, 4, NULL, &size, NULL, 0); +		if (st == -1) { +			_kvm_syserr(kd, kd->program, "kvm_getprocs"); +			return (0); +		} +		kd->procbase = (struct kinfo_proc *)_kvm_malloc(kd, size); +		if (kd->procbase == 0) +			return (0); +		st = sysctl(mib, 4, kd->procbase, &size, NULL, 0); +		if (st == -1) { +			_kvm_syserr(kd, kd->program, "kvm_getprocs"); +			return (0); +		} +		if (size % sizeof(struct kinfo_proc) != 0) { +			_kvm_err(kd, kd->program, +				"proc size mismatch (%d total, %d chunks)", +				size, sizeof(struct kinfo_proc)); +			return (0); +		} +		nprocs = size / sizeof(struct kinfo_proc); +	} else { +		struct nlist nl[4], *p; + +		nl[0].n_name = "_nprocs"; +		nl[1].n_name = "_allproc"; +		nl[2].n_name = "_zombproc"; +		nl[3].n_name = 0; + +		if (kvm_nlist(kd, nl) != 0) { +			for (p = nl; p->n_type != 0; ++p) +				; +			_kvm_err(kd, kd->program, +				 "%s: no such symbol", p->n_name); +			return (0); +		} +		if (KREAD(kd, nl[0].n_value, &nprocs)) { +			_kvm_err(kd, kd->program, "can't read nprocs"); +			return (0); +		} +		size = nprocs * sizeof(struct kinfo_proc); +		kd->procbase = (struct kinfo_proc *)_kvm_malloc(kd, size); +		if (kd->procbase == 0) +			return (0); + +		nprocs = kvm_deadprocs(kd, op, arg, nl[1].n_value, +				      nl[2].n_value, nprocs); +#ifdef notdef +		size = nprocs * sizeof(struct kinfo_proc); +		(void)realloc(kd->procbase, size); +#endif +	} +	*cnt = nprocs; +	return (kd->procbase); +} + +void +_kvm_freeprocs(kd) +	kvm_t *kd; +{ +	if (kd->procbase) { +		free(kd->procbase); +		kd->procbase = 0; +	} +} + +void * +_kvm_realloc(kd, p, n) +	kvm_t *kd; +	void *p; +	size_t n; +{ +	void *np = (void *)realloc(p, n); + +	if (np == 0) +		_kvm_err(kd, kd->program, "out of memory"); +	return (np); +} + +#ifndef MAX +#define MAX(a, b) ((a) > (b) ? (a) : (b)) +#endif + +/* + * Read in an argument vector from the user address space of process p. + * addr if the user-space base address of narg null-terminated contiguous  + * strings.  This is used to read in both the command arguments and + * environment strings.  Read at most maxcnt characters of strings. + */ +static char ** +kvm_argv(kd, p, addr, narg, maxcnt) +	kvm_t *kd; +	struct proc *p; +	register u_long addr; +	register int narg; +	register int maxcnt; +{ +	register char *cp; +	register int len, cc; +	register char **argv; + +	/* +	 * Check that there aren't an unreasonable number of agruments, +	 * and that the address is in user space. +	 */ +	if (narg > 512 || addr < VM_MIN_ADDRESS || addr >= VM_MAXUSER_ADDRESS) +		return (0); + +	if (kd->argv == 0) { +		/* +		 * Try to avoid reallocs. +		 */ +		kd->argc = MAX(narg + 1, 32); +		kd->argv = (char **)_kvm_malloc(kd, kd->argc *  +						sizeof(*kd->argv)); +		if (kd->argv == 0) +			return (0); +	} else if (narg + 1 > kd->argc) { +		kd->argc = MAX(2 * kd->argc, narg + 1); +		kd->argv = (char **)_kvm_realloc(kd, kd->argv, kd->argc *  +						sizeof(*kd->argv)); +		if (kd->argv == 0) +			return (0); +	} +	if (kd->argspc == 0) { +		kd->argspc = (char *)_kvm_malloc(kd, NBPG); +		if (kd->argspc == 0) +			return (0); +		kd->arglen = NBPG; +	} +	cp = kd->argspc; +	argv = kd->argv; +	*argv = cp; +	len = 0; +	/* +	 * Loop over pages, filling in the argument vector. +	 */ +	while (addr < VM_MAXUSER_ADDRESS) { +		cc = NBPG - (addr & PGOFSET); +		if (maxcnt > 0 && cc > maxcnt - len) +			cc = maxcnt - len;; +		if (len + cc > kd->arglen) { +			register int off; +			register char **pp; +			register char *op = kd->argspc; + +			kd->arglen *= 2; +			kd->argspc = (char *)_kvm_realloc(kd, kd->argspc, +							  kd->arglen); +			if (kd->argspc == 0) +				return (0); +			cp = &kd->argspc[len]; +			/* +			 * Adjust argv pointers in case realloc moved +			 * the string space. +			 */ +			off = kd->argspc - op; +			for (pp = kd->argv; pp < argv; ++pp) +				*pp += off; +		} +		if (kvm_uread(kd, p, addr, cp, cc) != cc) +			/* XXX */ +			return (0); +		len += cc; +		addr += cc; + +		if (maxcnt == 0 && len > 16 * NBPG) +			/* sanity */ +			return (0); + +		while (--cc >= 0) { +			if (*cp++ == 0) { +				if (--narg <= 0) { +					*++argv = 0; +					return (kd->argv); +				} else +					*++argv = cp; +			} +		} +		if (maxcnt > 0 && len >= maxcnt) { +			/* +			 * We're stopping prematurely.  Terminate the +			 * argv and current string. +			 */ +			*++argv = 0; +			*cp = 0; +			return (kd->argv); +		} +	} +} + +static void +ps_str_a(p, addr, n) +	struct ps_strings *p; +	u_long *addr; +	int *n; +{ +	*addr = (u_long)p->ps_argvstr; +	*n = p->ps_nargvstr; +} + +static void +ps_str_e(p, addr, n) +	struct ps_strings *p; +	u_long *addr; +	int *n; +{ +	*addr = (u_long)p->ps_envstr; +	*n = p->ps_nenvstr; +} + +/* + * Determine if the proc indicated by p is still active. + * This test is not 100% foolproof in theory, but chances of + * being wrong are very low. + */ +static int +proc_verify(kd, kernp, p) +	kvm_t *kd; +	u_long kernp; +	const struct proc *p; +{ +	struct proc kernproc; + +	/* +	 * Just read in the whole proc.  It's not that big relative +	 * to the cost of the read system call. +	 */ +	if (kvm_read(kd, kernp, (char *)&kernproc, sizeof(kernproc)) !=  +	    sizeof(kernproc)) +		return (0); +	return (p->p_pid == kernproc.p_pid && +		(kernproc.p_stat != SZOMB || p->p_stat == SZOMB)); +} + +static char ** +kvm_doargv(kd, kp, nchr, info) +	kvm_t *kd; +	const struct kinfo_proc *kp; +	int nchr; +	int (*info)(struct ps_strings*, u_long *, int *); +{ +	register const struct proc *p = &kp->kp_proc; +	register char **ap; +	u_long addr; +	int cnt; +	struct ps_strings arginfo; + +	/* +	 * Pointers are stored at the top of the user stack. +	 */ +	if (p->p_stat == SZOMB ||  +	    kvm_uread(kd, p, USRSTACK - sizeof(arginfo), (char *)&arginfo, +		      sizeof(arginfo)) != sizeof(arginfo)) +		return (0); + +	(*info)(&arginfo, &addr, &cnt); +	ap = kvm_argv(kd, p, addr, cnt, nchr); +	/* +	 * For live kernels, make sure this process didn't go away. +	 */ +	if (ap != 0 && ISALIVE(kd) && +	    !proc_verify(kd, (u_long)kp->kp_eproc.e_paddr, p)) +		ap = 0; +	return (ap); +} + +/* + * Get the command args.  This code is now machine independent. + */ +char ** +kvm_getargv(kd, kp, nchr) +	kvm_t *kd; +	const struct kinfo_proc *kp; +	int nchr; +{ +	return (kvm_doargv(kd, kp, nchr, ps_str_a)); +} + +char ** +kvm_getenvv(kd, kp, nchr) +	kvm_t *kd; +	const struct kinfo_proc *kp; +	int nchr; +{ +	return (kvm_doargv(kd, kp, nchr, ps_str_e)); +} + +/* + * Read from user space.  The user context is given by p. + */ +ssize_t +kvm_uread(kd, p, uva, buf, len) +	kvm_t *kd; +	register struct proc *p; +	register u_long uva; +	register char *buf; +	register size_t len; +{ +	register char *cp; + +	cp = buf; +	while (len > 0) { +		u_long pa; +		register int cc; +		 +		cc = _kvm_uvatop(kd, p, uva, &pa); +		if (cc > 0) { +			if (cc > len) +				cc = len; +			errno = 0; +			if (lseek(kd->pmfd, (off_t)pa, 0) == -1 && errno != 0) { +				_kvm_err(kd, 0, "invalid address (%x)", uva); +				break; +			} +			cc = read(kd->pmfd, cp, cc); +			if (cc < 0) { +				_kvm_syserr(kd, 0, _PATH_MEM); +				break; +			} else if (cc < len) { +				_kvm_err(kd, kd->program, "short read"); +				break; +			} +		} else if (ISALIVE(kd)) { +			/* try swap */ +			register char *dp; +			int cnt; + +			dp = kvm_readswap(kd, p, uva, &cnt); +			if (dp == 0) { +				_kvm_err(kd, 0, "invalid address (%x)", uva); +				return (0); +			} +			cc = MIN(cnt, len); +			bcopy(dp, cp, cc); +		} else +			break; +		cp += cc; +		uva += cc; +		len -= cc; +	} +	return (ssize_t)(cp - buf); +} diff --git a/lib/libm/common_source/math.3 b/lib/libm/common_source/math.3 new file mode 100644 index 000000000000..80947e6854be --- /dev/null +++ b/lib/libm/common_source/math.3 @@ -0,0 +1,630 @@ +.\" Copyright (c) 1985, 1993 +.\"	The 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. +.\" +.\"	@(#)math.3	8.2 (Berkeley) 5/5/94 +.\" +.TH MATH 3 "May 5, 1994" +.UC 4 +.ds up \fIulp\fR +.ds nn \fINaN\fR +.de If +.if n \\ +\\$1Infinity\\$2 +.if t \\ +\\$1\\(if\\$2 +.. +.SH NAME +math \- introduction to mathematical library functions +.SH DESCRIPTION +These functions constitute the C math library, +.I libm. +The link editor searches this library under the \*(lq\-lm\*(rq option. +Declarations for these functions may be obtained from the include file +.RI < math.h >. +The Fortran math library is described in ``man 3f intro''. +.SH "LIST OF FUNCTIONS" +.sp 2 +.nf +.ta \w'copysign'u+2n +\w'infnan.3m'u+10n +\w'inverse trigonometric func'u +\fIName\fP	\fIAppears on Page\fP	\fIDescription\fP	\fIError Bound (ULPs)\fP +.ta \w'copysign'u+4n +\w'infnan.3m'u+4n +\w'inverse trigonometric function'u+6nC +.sp 5p +acos	sin.3m	inverse trigonometric function	3 +acosh	asinh.3m	inverse hyperbolic function	3 +asin	sin.3m	inverse trigonometric function	3 +asinh	asinh.3m	inverse hyperbolic function	3 +atan	sin.3m	inverse trigonometric function	1 +atanh	asinh.3m	inverse hyperbolic function	3 +atan2	sin.3m	inverse trigonometric function	2 +cabs	hypot.3m	complex absolute value	1 +cbrt	sqrt.3m	cube root	1 +ceil	floor.3m	integer no less than	0 +copysign	ieee.3m	copy sign bit	0 +cos	sin.3m	trigonometric function	1 +cosh	sinh.3m	hyperbolic function	3 +drem	ieee.3m	remainder	0 +erf	erf.3m	error function	??? +erfc	erf.3m	complementary error function	??? +exp	exp.3m	exponential	1 +expm1	exp.3m	exp(x)\-1	1 +fabs	floor.3m	absolute value	0 +floor	floor.3m	integer no greater than	0 +hypot	hypot.3m	Euclidean distance	1 +infnan	infnan.3m	signals exceptions +j0	j0.3m	bessel function	??? +j1	j0.3m	bessel function	??? +jn	j0.3m	bessel function	??? +lgamma	lgamma.3m	log gamma function; (formerly gamma.3m) +log	exp.3m	natural logarithm	1 +logb	ieee.3m	exponent extraction	0 +log10	exp.3m	logarithm to base 10	3 +log1p	exp.3m	log(1+x)	1 +pow	exp.3m	exponential x**y	60\-500 +rint	floor.3m	round to nearest integer	0 +scalb	ieee.3m	exponent adjustment	0 +sin	sin.3m	trigonometric function	1 +sinh	sinh.3m	hyperbolic function	3 +sqrt	sqrt.3m	square root	1 +tan	sin.3m	trigonometric function	3 +tanh	sinh.3m	hyperbolic function	3 +y0	j0.3m	bessel function	??? +y1	j0.3m	bessel function	??? +yn	j0.3m	bessel function	??? +.ta +.fi +.SH NOTES +In 4.3 BSD, distributed from the University of California +in late 1985, most of the foregoing functions come in two +versions, one for the double\-precision "D" format in the +DEC VAX\-11 family of computers, another for double\-precision +arithmetic conforming to the IEEE Standard 754 for Binary +Floating\-Point Arithmetic.  The two versions behave very +similarly, as should be expected from programs more accurate +and robust than was the norm when UNIX was born.  For +instance, the programs are accurate to within the numbers +of \*(ups tabulated above; an \*(up is one \fIU\fRnit in the \fIL\fRast +\fIP\fRlace.  And the programs have been cured of anomalies that +afflicted the older math library \fIlibm\fR in which incidents like +the following had been reported: +.RS +sqrt(\-1.0) = 0.0 and log(\-1.0) = \-1.7e38. +.br +cos(1.0e\-11) > cos(0.0) > 1.0. +.br +pow(x,1.0) +.if n \ +!= +.if t \ +\(!= +x when x = 2.0, 3.0, 4.0, ..., 9.0. +.br +pow(\-1.0,1.0e10) trapped on Integer Overflow. +.br +sqrt(1.0e30) and sqrt(1.0e\-30) were very slow. +.RE +However the two versions do differ in ways that have to be +explained, to which end the following notes are provided. +.PP +\fBDEC VAX\-11 D_floating\-point:\fR +.PP +This is the format for which the original math library \fIlibm\fR +was developed, and to which this manual is still principally +dedicated.  It is \fIthe\fR double\-precision format for the PDP\-11 +and the earlier VAX\-11 machines; VAX\-11s after 1983 were +provided with an optional "G" format closer to the IEEE +double\-precision format.  The earlier DEC MicroVAXs have no +D format, only G double\-precision. (Why?  Why not?) +.PP +Properties of D_floating\-point: +.RS +Wordsize: 64 bits, 8 bytes.  Radix: Binary. +.br +Precision: 56 +.if n \ +sig. +.if t \ +significant +bits, roughly like 17 +.if n \ +sig. +.if t \ +significant +decimals. +.RS +If x and x' are consecutive positive D_floating\-point +numbers (they differ by 1 \*(up), then +.br +1.3e\-17 < 0.5**56 < (x'\-x)/x \(<= 0.5**55 < 2.8e\-17. +.RE +.nf +.ta \w'Range:'u+1n +\w'Underflow threshold'u+1n +\w'= 2.0**127'u+1n +Range:	Overflow threshold	= 2.0**127	= 1.7e38. +	Underflow threshold	= 0.5**128	= 2.9e\-39. +	NOTE:  THIS RANGE IS COMPARATIVELY NARROW. +.ta +.fi +.RS +Overflow customarily stops computation. +.br +Underflow is customarily flushed quietly to zero. +.br +CAUTION: +.RS +It is possible to have x +.if n \ +!= +.if t \ +\(!= +y and yet +x\-y = 0 because of underflow.  Similarly +x > y > 0 cannot prevent either x\(**y = 0 +or  y/x = 0 from happening without warning. +.RE +.RE +Zero is represented ambiguously. +.RS +Although 2**55 different representations of zero are accepted by +the hardware, only the obvious representation is ever produced. +There is no \-0 on a VAX. +.RE +.If +is not part of the VAX architecture. +.br +Reserved operands: +.RS +of the 2**55 that the hardware +recognizes, only one of them is ever produced. +Any floating\-point operation upon a reserved +operand, even a MOVF or MOVD, customarily stops +computation, so they are not much used. +.RE +Exceptions: +.RS +Divisions by zero and operations that +overflow are invalid operations that customarily +stop computation or, in earlier machines, produce +reserved operands that will stop computation. +.RE +Rounding: +.RS +Every rational operation  (+, \-, \(**, /) on a +VAX (but not necessarily on a PDP\-11), if not an +over/underflow nor division by zero, is rounded to +within half an \*(up, and when the rounding error is +exactly half an \*(up then rounding is away from 0. +.RE +.RE +.PP +Except for its narrow range, D_floating\-point is one of the +better computer arithmetics designed in the 1960's. +Its properties are reflected fairly faithfully in the elementary +functions for a VAX distributed in 4.3 BSD. +They over/underflow only if their results have to lie out of range +or very nearly so, and then they behave much as any rational +arithmetic operation that over/underflowed would behave. +Similarly, expressions like log(0) and atanh(1) behave +like 1/0; and sqrt(\-3) and acos(3) behave like 0/0; +they all produce reserved operands and/or stop computation! +The situation is described in more detail in manual pages. +.RS +.ll -0.5i +\fIThis response seems excessively punitive, so it is destined +to be replaced at some time in the foreseeable future by a +more flexible but still uniform scheme being developed to +handle all floating\-point arithmetic exceptions neatly. +See infnan(3M) for the present state of affairs.\fR +.ll +0.5i +.RE +.PP +How do the functions in 4.3 BSD's new \fIlibm\fR for UNIX +compare with their counterparts in DEC's VAX/VMS library? +Some of the VMS functions are a little faster, some are +a little more accurate, some are more puritanical about +exceptions (like pow(0.0,0.0) and atan2(0.0,0.0)), +and most occupy much more memory than their counterparts in +\fIlibm\fR. +The VMS codes interpolate in large table to achieve +speed and accuracy; the \fIlibm\fR codes use tricky formulas +compact enough that all of them may some day fit into a ROM. +.PP +More important, DEC regards the VMS codes as proprietary +and guards them zealously against unauthorized use.  But the +\fIlibm\fR codes in 4.3 BSD are intended for the public domain; +they may be copied freely provided their provenance is always +acknowledged, and provided users assist the authors in their +researches by reporting experience with the codes. +Therefore no user of UNIX on a machine whose arithmetic resembles +VAX D_floating\-point need use anything worse than the new \fIlibm\fR. +.PP +\fBIEEE STANDARD 754 Floating\-Point Arithmetic:\fR +.PP +This standard is on its way to becoming more widely adopted +than any other design for computer arithmetic. +VLSI chips that conform to some version of that standard have been +produced by a host of manufacturers, among them ... +.nf +.ta 0.5i +\w'Intel i8070, i80287'u+6n +	Intel i8087, i80287	National Semiconductor  32081 +	Motorola 68881	Weitek WTL-1032, ... , -1165 +	Zilog Z8070	Western Electric (AT&T) WE32106. +.ta +.fi +Other implementations range from software, done thoroughly +in the Apple Macintosh, through VLSI in the Hewlett\-Packard +9000 series, to the ELXSI 6400 running ECL at 3 Megaflops. +Several other companies have adopted the formats +of IEEE 754 without, alas, adhering to the standard's way +of handling rounding and exceptions like over/underflow. +The DEC VAX G_floating\-point format is very similar to the IEEE +754 Double format, so similar that the C programs for the +IEEE versions of most of the elementary functions listed +above could easily be converted to run on a MicroVAX, though +nobody has volunteered to do that yet. +.PP +The codes in 4.3 BSD's \fIlibm\fR for machines that conform to +IEEE 754 are intended primarily for the National Semi. 32081 +and WTL 1164/65.  To use these codes with the Intel or Zilog +chips, or with the Apple Macintosh or ELXSI 6400, is to +forego the use of better codes provided (perhaps freely) by +those companies and designed by some of the authors of the +codes above. +Except for \fIatan\fR, \fIcabs\fR, \fIcbrt\fR, \fIerf\fR, +\fIerfc\fR, \fIhypot\fR, \fIj0\-jn\fR, \fIlgamma\fR, \fIpow\fR +and \fIy0\-yn\fR, +the Motorola 68881 has all the functions in \fIlibm\fR on chip, +and faster and more accurate; +it, Apple, the i8087, Z8070 and WE32106 all use 64 +.if n \ +sig. +.if t \ +significant +bits. +The main virtue of 4.3 BSD's +\fIlibm\fR codes is that they are intended for the public domain; +they may be copied freely provided their provenance is always +acknowledged, and provided users assist the authors in their +researches by reporting experience with the codes. +Therefore no user of UNIX on a machine that conforms to +IEEE 754 need use anything worse than the new \fIlibm\fR. +.PP +Properties of IEEE 754 Double\-Precision: +.RS +Wordsize: 64 bits, 8 bytes.  Radix: Binary. +.br +Precision: 53 +.if n \ +sig. +.if t \ +significant +bits, roughly like 16 +.if n \ +sig. +.if t \ +significant +decimals. +.RS +If x and x' are consecutive positive Double\-Precision +numbers (they differ by 1 \*(up), then +.br +1.1e\-16 < 0.5**53 < (x'\-x)/x \(<= 0.5**52 < 2.3e\-16. +.RE +.nf +.ta \w'Range:'u+1n +\w'Underflow threshold'u+1n +\w'= 2.0**1024'u+1n +Range:	Overflow threshold	= 2.0**1024	= 1.8e308 +	Underflow threshold	= 0.5**1022	= 2.2e\-308 +.ta +.fi +.RS +Overflow goes by default to a signed +.If "" . +.br +Underflow is \fIGradual,\fR rounding to the nearest +integer multiple of 0.5**1074 = 4.9e\-324. +.RE +Zero is represented ambiguously as +0 or \-0. +.RS +Its sign transforms correctly through multiplication or +division, and is preserved by addition of zeros +with like signs; but x\-x yields +0 for every +finite x.  The only operations that reveal zero's +sign are division by zero and copysign(x,\(+-0). +In particular, comparison (x > y, x \(>= y, etc.) +cannot be affected by the sign of zero; but if +finite x = y then +.If +\&= 1/(x\-y) +.if n \ +!= +.if t \ +\(!= +\-1/(y\-x) = +.If \- . +.RE +.If +is signed. +.RS +it persists when added to itself +or to any finite number.  Its sign transforms +correctly through multiplication and division, and +.If (finite)/\(+- \0=\0\(+-0 +(nonzero)/0 = +.If \(+- . +But  +.if n \ +Infinity\-Infinity, Infinity\(**0 and Infinity/Infinity +.if t \ +\(if\-\(if, \(if\(**0 and \(if/\(if +are, like 0/0 and sqrt(\-3), +invalid operations that produce \*(nn. ... +.RE +Reserved operands: +.RS +there are 2**53\-2 of them, all +called \*(nn (\fIN\fRot \fIa N\fRumber). +Some, called Signaling \*(nns, trap any floating\-point operation +performed upon them; they are used to mark missing +or uninitialized values, or nonexistent elements +of arrays.  The rest are Quiet \*(nns; they are +the default results of Invalid Operations, and +propagate through subsequent arithmetic operations. +If x +.if n \ +!= +.if t \ +\(!= +x then x is \*(nn; every other predicate +(x > y, x = y, x < y, ...) is FALSE if \*(nn is involved. +.br +NOTE: Trichotomy is violated by \*(nn. +.RS +Besides being FALSE, predicates that entail ordered +comparison, rather than mere (in)equality, +signal Invalid Operation when \*(nn is involved. +.RE +.RE +Rounding: +.RS +Every algebraic operation (+, \-, \(**, /, +.if n \ +sqrt) +.if t \ +\(sr) +is rounded by default to within half an \*(up, and +when the rounding error is exactly half an \*(up then +the rounded value's least significant bit is zero. +This kind of rounding is usually the best kind, +sometimes provably so; for instance, for every +x = 1.0, 2.0, 3.0, 4.0, ..., 2.0**52, we find +(x/3.0)\(**3.0 == x and (x/10.0)\(**10.0 == x and ... +despite that both the quotients and the products +have been rounded.  Only rounding like IEEE 754 +can do that.  But no single kind of rounding can be +proved best for every circumstance, so IEEE 754 +provides rounding towards zero or towards +.If + +or towards +.If \- +at the programmer's option.  And the +same kinds of rounding are specified for +Binary\-Decimal Conversions, at least for magnitudes +between roughly 1.0e\-10 and 1.0e37. +.RE +Exceptions: +.RS +IEEE 754 recognizes five kinds of floating\-point exceptions, +listed below in declining order of probable importance. +.RS +.nf +.ta \w'Invalid Operation'u+6n +\w'Gradual Underflow'u+2n +Exception	Default Result +.sp 0.5 +Invalid Operation	\*(nn, or FALSE +.if n \{\ +Overflow	\(+-Infinity +Divide by Zero	\(+-Infinity \} +.if t \{\ +Overflow	\(+-\(if +Divide by Zero	\(+-\(if \} +Underflow	Gradual Underflow +Inexact	Rounded value +.ta +.fi +.RE +NOTE:  An Exception is not an Error unless handled +badly.  What makes a class of exceptions exceptional +is that no single default response can be satisfactory +in every instance.  On the other hand, if a default +response will serve most instances satisfactorily, +the unsatisfactory instances cannot justify aborting +computation every time the exception occurs. +.RE +.PP +For each kind of floating\-point exception, IEEE 754 +provides a Flag that is raised each time its exception +is signaled, and stays raised until the program resets +it.  Programs may also test, save and restore a flag. +Thus, IEEE 754 provides three ways by which programs +may cope with exceptions for which the default result +might be unsatisfactory: +.IP 1) \w'\0\0\0\0'u +Test for a condition that might cause an exception +later, and branch to avoid the exception. +.IP 2) \w'\0\0\0\0'u +Test a flag to see whether an exception has occurred +since the program last reset its flag. +.IP 3) \w'\0\0\0\0'u +Test a result to see whether it is a value that only +an exception could have produced. +.RS +CAUTION: The only reliable ways to discover +whether Underflow has occurred are to test whether +products or quotients lie closer to zero than the +underflow threshold, or to test the Underflow +flag.  (Sums and differences cannot underflow in +IEEE 754; if x +.if n \ +!= +.if t \ +\(!= +y then x\-y is correct to +full precision and certainly nonzero regardless of +how tiny it may be.)  Products and quotients that +underflow gradually can lose accuracy gradually +without vanishing, so comparing them with zero +(as one might on a VAX) will not reveal the loss. +Fortunately, if a gradually underflowed value is +destined to be added to something bigger than the +underflow threshold, as is almost always the case, +digits lost to gradual underflow will not be missed +because they would have been rounded off anyway. +So gradual underflows are usually \fIprovably\fR ignorable. +The same cannot be said of underflows flushed to 0. +.RE +.PP +At the option of an implementor conforming to IEEE 754, +other ways to cope with exceptions may be provided: +.IP 4) \w'\0\0\0\0'u +ABORT.  This mechanism classifies an exception in +advance as an incident to be handled by means +traditionally associated with error\-handling +statements like "ON ERROR GO TO ...".  Different +languages offer different forms of this statement, +but most share the following characteristics: +.IP \(em \w'\0\0\0\0'u +No means is provided to substitute a value for +the offending operation's result and resume +computation from what may be the middle of an +expression.  An exceptional result is abandoned. +.IP \(em \w'\0\0\0\0'u +In a subprogram that lacks an error\-handling +statement, an exception causes the subprogram to +abort within whatever program called it, and so +on back up the chain of calling subprograms until +an error\-handling statement is encountered or the +whole task is aborted and memory is dumped. +.IP 5) \w'\0\0\0\0'u +STOP.  This mechanism, requiring an interactive +debugging environment, is more for the programmer +than the program.  It classifies an exception in +advance as a symptom of a programmer's error; the +exception suspends execution as near as it can to +the offending operation so that the programmer can +look around to see how it happened.  Quite often +the first several exceptions turn out to be quite +unexceptionable, so the programmer ought ideally +to be able to resume execution after each one as if +execution had not been stopped. +.IP 6) \w'\0\0\0\0'u +\&... Other ways lie beyond the scope of this document. +.RE +.PP +The crucial problem for exception handling is the problem of +Scope, and the problem's solution is understood, but not +enough manpower was available to implement it fully in time +to be distributed in 4.3 BSD's \fIlibm\fR.  Ideally, each +elementary function should act as if it were indivisible, or +atomic, in the sense that ... +.IP i) \w'iii)'u+2n +No exception should be signaled that is not deserved by +the data supplied to that function. +.IP ii) \w'iii)'u+2n +Any exception signaled should be identified with that +function rather than with one of its subroutines. +.IP iii) \w'iii)'u+2n +The internal behavior of an atomic function should not +be disrupted when a calling program changes from +one to another of the five or so ways of handling +exceptions listed above, although the definition +of the function may be correlated intentionally +with exception handling. +.PP +Ideally, every programmer should be able \fIconveniently\fR to +turn a debugged subprogram into one that appears atomic to +its users.  But simulating all three characteristics of an +atomic function is still a tedious affair, entailing hosts +of tests and saves\-restores; work is under way to ameliorate +the inconvenience. +.PP +Meanwhile, the functions in \fIlibm\fR are only approximately +atomic.  They signal no inappropriate exception except +possibly ... +.RS +Over/Underflow +.RS +when a result, if properly computed, might have lain barely within range, and +.RE +Inexact in \fIcabs\fR, \fIcbrt\fR, \fIhypot\fR, \fIlog10\fR and \fIpow\fR +.RS +when it happens to be exact, thanks to fortuitous cancellation of errors. +.RE +.RE +Otherwise, ... +.RS +Invalid Operation is signaled only when +.RS +any result but \*(nn would probably be misleading. +.RE +Overflow is signaled only when +.RS +the exact result would be finite but beyond the overflow threshold. +.RE +Divide\-by\-Zero is signaled only when +.RS +a function takes exactly infinite values at finite operands. +.RE +Underflow is signaled only when +.RS +the exact result would be nonzero but tinier than the underflow threshold. +.RE +Inexact is signaled only when +.RS +greater range or precision would be needed to represent the exact result. +.RE +.RE +.SH BUGS +When signals are appropriate, they are emitted by certain +operations within the codes, so a subroutine\-trace may be +needed to identify the function with its signal in case +method 5) above is in use.  And the codes all take the +IEEE 754 defaults for granted; this means that a decision to +trap all divisions by zero could disrupt a code that would +otherwise get correct results despite division by zero. +.SH SEE ALSO +An explanation of IEEE 754 and its proposed extension p854 +was published in the IEEE magazine MICRO in August 1984 under +the title "A Proposed Radix\- and Word\-length\-independent +Standard for Floating\-point Arithmetic" by W. J. Cody et al. +The manuals for Pascal, C and BASIC on the Apple Macintosh +document the features of IEEE 754 pretty well. +Articles in the IEEE magazine COMPUTER vol. 14 no. 3 (Mar. +1981), and in the ACM SIGNUM Newsletter Special Issue of +Oct. 1979, may be helpful although they pertain to +superseded drafts of the standard. diff --git a/lib/librpc/DISCLAIMER b/lib/librpc/DISCLAIMER new file mode 100644 index 000000000000..1a66d5f4c9cd --- /dev/null +++ b/lib/librpc/DISCLAIMER @@ -0,0 +1,28 @@ +/* + * Sun RPC is a product of Sun Microsystems, Inc. and is provided for + * unrestricted use provided that this legend is included on all tape + * media and as a part of the software program in whole or part.  Users + * may copy or modify Sun RPC without charge, but are not authorized + * to license or distribute it to anyone else except as part of a product or + * program developed by the user. + *  + * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE + * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR + * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. + *  + * Sun RPC is provided with no support and without any obligation on the + * part of Sun Microsystems, Inc. to assist in its use, correction, + * modification or enhancement. + *  + * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE + * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC + * OR ANY PART THEREOF. + *  + * In no event will Sun Microsystems, Inc. be liable for any lost revenue + * or profits or other special, indirect and consequential damages, even if + * Sun has been advised of the possibility of such damages. + *  + * Sun Microsystems, Inc. + * 2550 Garcia Avenue + * Mountain View, California  94043 + */ diff --git a/lib/librpc/Makefile b/lib/librpc/Makefile new file mode 100644 index 000000000000..bafff291ebd0 --- /dev/null +++ b/lib/librpc/Makefile @@ -0,0 +1,30 @@ +# +# @(#)Makefile	2.1 88/08/11 4.0 RPCSRC +# +#   Build and install everything. +# +# These directories are presumed to exist in DESTDIR: +#    /usr/lib /usr/bin /usr/include +# +DESTDIR= +CFLAGS=-O +MAKE=make + +# These are not used by BSD except portmap which lives in +# /usr/src/usr.sbin/portmap. +# SUBDIR= rpcgen etc rpcsvc + +all install:	rpclib ${SUBDIR} + +rpclib:	FRC +	@echo "Building and installing RPC library" +	cd rpc; $(MAKE) ${MFLAGS} all DESTDIR=${DESTDIR}; \ +        $(MAKE) ${MFLAGS} install DESTDIR=${DESTDIR} + +${SUBDIR}:	FRC +	@echo "Building and installing files from: $@" +	cd $@; $(MAKE) ${MFLAGS} DESTDIR=${DESTDIR} CFLAGS=${CFLAGS};\ +        $(MAKE) ${MFLAGS} install DESTDIR=${DESTDIR} + +FRC: + diff --git a/lib/librpc/README b/lib/librpc/README new file mode 100644 index 000000000000..ad9d70f99056 --- /dev/null +++ b/lib/librpc/README @@ -0,0 +1,233 @@ +RPCSRC 4.0 7/11/89 + +This distribution contains Sun Microsystem's implementation of the +RPC and XDR protocols and is compatible with 4.2BSD and 4.3BSD.  Also +included is complete documentation, utilities, RPC service +specification files, and demonstration services in the format used by +the RPC protocol compiler (rpcgen).  See WHAT'S NEW below for +details. + +NOTE ABOUT SECURE RPC: + +This release of RPCSRC contains most of the code needed to implement +Secure RPC (see "DES Authentication" in the RPC Protocol Specification, +doc/rpc.rfc.ms).  Due to legal considerations, we are unable to +distribute an implementation of DES, the Data Encryption Standard, which +Secure RPC requires.  For this reason, all of the files, documentation, and +programs associated with Secure RPC have been placed into a separate +directory, secure_rpc.  The RPC library contained in the main body of this +release *DOES NOT* support Secure RPC.  See secure_rpc/README for more +details.  (A DES library was posted in Volume 18 of comp.sources.unix.) + +If you wish to report bugs found in this release, send mail to: + +Portable ONC/NFS +Sun Microsystems, Inc +MS 12-33 +2550 Garcia Avenue +Mountain View, CA  94043 + +or send Email to nfsnet@sun.com (the Internet) or sun!nfsnet (Usenet). + +ROADMAP + +The directory hierarchy is as follows: + +    demo/       Various demonstration services +    demo/dir        Remote directory lister +    demo/msg        Remote console message delivery service +    demo/sort       Remote sort service + +    doc/        Documentation for RPC, XDR and NFS in "-ms" format. + +    etc/        Utilities (rpcinfo and portmap).  portmap must be +                started by root before any other RPC network services are +                used.  SEE BELOW FOR BUGFIX TO 4.3BSD COMPILER. + +    man/        Manual pages for RPC library, rpcgen, and utilities. + +    rpc/        The RPC and XDR library.  SEE BELOW +                FOR BUGFIX TO 4.2BSD COMPILER. + +    rpcgen/     The RPC Language compiler (for .x files) + +    rpcsvc/     Service definition files for various services and the +                server and client code for the Remote Status service. + +    secure_rpc/ The files in this directory are used to build a version of +                the RPC library with DES Authentication.  See the README +                file in that directory for more details. + +BUILD INSTRUCTIONS + +Makefiles can be found in all directories except for man.  The +Makefile in the top directory will cause these others to be invoked +(except for in the doc, man and demo directories), in turn building the +entire release. + +WARNING!  THE DEFAULT INSTALLATION PROCEDURES WILL INSTALL FILES +IN /usr/include, /usr/lib, /usr/bin and /etc. + +The master RPC include file, rpc/rpc.h, is used by all programs and +routines that use RPC.  It includes other RPC and system include files +needed by the RPC system.  PLEASE NOTE: If your system has NFS, it +may have been based on Sun's NFS Source.  The include files installed +by this package may duplicate include files you will find on your NFS +system.  The RPCSRC 4.0 include files are upwardly compatible to all +NFS Source include files as of the date of this distribution (not +including any new definitions or declarations added by your system +vendor).  HOWEVER: Please read the comments towards the end of +rpc/rpc.h regarding rpc/netdb.h.  You may need to uncomment the +inclusion of that file if the structures it defines are already +defined by your system's include files. + +After making any compiler fixes that are needed (see below), at +the top directory, type: + +    make install + +For all installations, the Makefile macro DESTDIR is prepended to the +installation path.  It is defined to be null in the Makefiles, so +installations are relative to root.  (You will probably need root +privileges for installing the files under the default path.)  To +install the files under some other tree (e.g., /usr/local), use the +command: + +    make install DESTDIR=/usr/local + +This will place the include files in /usr/local/usr/include, the RPC +library in /usr/local/usr/lib, rpcgen in /usr/local/usr/bin, and the +utilities in /usr/local/etc.  You'll have to edit the Makefiles or +install the files by hand if you want to do anything other than this +kind of relocation of the installation tree. + +The RPC library will be built and installed first.  By default it is +installed in /usr/lib as "librpclib.a".  The directory +/usr/include/rpc will also be created, and several header files will +be installed there.  ALL RPC SERVICES INCLUDE THESE HEADER FILES. + +The programs in etc/ link in routines from librpclib.a.  If you change +where it is installed, be sure to edit etc/'s Makefile to reflect this. +These programs are installed in /etc.  PORTMAP MUST BE RUNNING ON +YOUR SYSTEM BEFORE YOU START ANY OTHER RPC SERVICE. + +rpcgen is installed in /usr/bin.  This program is required to build +the demonstration services in demo and the rstat client and server in +rpcsvc/. + +The rpcsvc/ directory will install its files in the directory +/usr/include/rpcsvc.  The Remote Status service (rstat_svc) will be +compiled and installed in /etc.  If you wish to make this service +available, you should either start this service when needed or have +it started at boot time by invoking it in your /etc/rc.local script. +(Be sure that portmap is started first!)  Sun has modified its +version of inetd to automatically start RPC services.  (Use "make +LIB=" when building rstat on a Sun Workstation.)  The Remote Status +client (rstat) will be installed in /usr/bin.  This program queries +the rstat_svc on a remote host and prints a system status summary +similar to the one printed by "uptime". + +The documentation is not built during the "make install" command. +Typing "make" in the doc directory will cause all of the manuals to +be formatted using nroff into a single file.  We have had a report +that certain "troff" equivalents have trouble processing the full +manual.  If you have trouble, try building the manuals individually +(see the Makefile). + +The demonstration services in the demo directory are not built by the +top-level "make install" command.  To build these, cd to the demo +directory and enter "make".  The three services will be built. +RPCGEN MUST BE INSTALLED in a path that make can find.  To run the +services, start the portmap program as root and invoke the service +(you probably will want to put it in the background).  rpcinfo can be +used to check that the service succeeded in getting registered with +portmap, and to ping the service (see rpcinfo's man page).  You can +then use the corresponding client program to exercise the service. +To build these services on a Sun workstation, you must prevent the +Makefile from trying to link the RPC library (as these routines are +already a part of Sun's libc).  Use: "make LIB=". + +BUGFIX FOR 4.3BSD COMPILER + +The use of a 'void *' declaration for one of the arguments in +the reply_proc() procedure in etc/rpcinfo.c will trigger a bug +in the 4.3BSD compiler.  The bug is fixed by the following change to +the compiler file mip/manifest.h: + +*** manifest.h.r1.1	Thu Apr 30 13:52:25 1987 +--- manifest.h.r1.2	Mon Nov 23 18:58:17 1987 +*************** +*** 21,27 **** +  /* +   * Bogus type values +   */ +! #define TNULL	PTR		/* pointer to UNDEF */ +  #define TVOID	FTN		/* function returning UNDEF (for void) */ +   +  /* +--- 21,27 ---- +  /* +   * Bogus type values +   */ +! #define TNULL	INCREF(MOETY)	/* pointer to MOETY -- impossible type */ +  #define TVOID	FTN		/* function returning UNDEF (for void) */ +   +  /* + +If you cannot fix your compiler, change the declaration in reply_proc() +from 'void *' to 'char *'. + +BUGFIX FOR 4.2BSD COMPILER + +Unpatched 4.2BSD compilers complain about valid C.  You can make old +compilers happy by changing some voids to ints.  However, the fix to +the 4.2 VAX compiler is as follows (to mip/trees.c): + +*** trees.c.r1.1	Mon May 11 13:47:58 1987 +--- trees.c.r1.2	Wed Jul  2 18:28:52 1986 +*************** +*** 1247,1253 **** +  		if(o==CAST && mt1==0)return(TYPL+TYMATCH); +  		if( mt12 & MDBI ) return( TYPL+LVAL+TYMATCH ); +  		else if( (mt1&MENU)||(mt2&MENU) ) return( LVAL+NCVT+TYPL+PTMATCH+PUN ); +! 		else if( mt12 == 0 ) break; +  		else if( mt1 & MPTR ) return( LVAL+PTMATCH+PUN ); +  		else if( mt12 & MPTI ) return( TYPL+LVAL+TYMATCH+PUN ); +  		break; +--- 1261,1269 ---- +  		if(o==CAST && mt1==0)return(TYPL+TYMATCH); +  		if( mt12 & MDBI ) return( TYPL+LVAL+TYMATCH ); +  		else if( (mt1&MENU)||(mt2&MENU) ) return( LVAL+NCVT+TYPL+PTMATCH+PUN ); +! 		/* if right is TVOID and looks like a CALL, is not ok */ +! 		else if (mt2 == 0 && (p->in.right->in.op == CALL || p->in.right->in.op == UNARY CALL)) +! 			break; +  		else if( mt1 & MPTR ) return( LVAL+PTMATCH+PUN ); +  		else if( mt12 & MPTI ) return( TYPL+LVAL+TYMATCH+PUN ); +  		break; + +WHAT'S NEW IN THIS RELEASE: RPCSRC 4.0 + +The previous release was RPCSRC 3.9.  As with all previous releases, +this release is based directly on files from Sun Microsystem's +implementation. + +Upgrade from RPCSRC 3.9 + +1)  RPCSRC 4.0 upgrades RPCSRC 3.9.  Improvements from SunOS 4.0 have +    been integrated into this release. + +Secure RPC (in the secure_rpc/ directory) + +2)  DES Authentication routines and programs are provided. +3)  A new manual, "Secure NFS" is provided, which describes Secure RPC +    and Secure NFS. +4)  Skeleton routines and manual pages are provided which describe the +    DES encryption procedures required by Secure RPC.  HOWEVER, NO DES +    ROUTINE IS PROVIDED. + +New Functionality + +5)  rpcinfo can now be used to de-register services from the portmapper +    which may have terminated abnormally. +6)  A new client, rstat, is provided which queries the rstat_svc and +    prints a status line similar to the one displayed by "uptime". diff --git a/lib/librpc/demo/Makefile b/lib/librpc/demo/Makefile new file mode 100644 index 000000000000..05510d64eb9f --- /dev/null +++ b/lib/librpc/demo/Makefile @@ -0,0 +1,25 @@ +# +# @(#)Makefile	2.1 88/08/02 4.0 RPCSRC +# +# +#   Build all demo services +# +MAKE = make +LIB=-lrpclib + +SUBDIR= dir msg sort + +all:	${SUBDIR} + +clean cleanup: +	cd dir; $(MAKE) ${MFLAGS} cleanup +	cd msg; $(MAKE) ${MFLAGS} cleanup +	cd sort; $(MAKE) ${MFLAGS} cleanup + +install: +	@echo "No installations done." + +${SUBDIR}:	FRC +	cd $@; $(MAKE) ${MFLAGS} LIB=$(LIB) + +FRC: diff --git a/lib/librpc/demo/dir/Makefile b/lib/librpc/demo/dir/Makefile new file mode 100644 index 000000000000..592c9d6861e9 --- /dev/null +++ b/lib/librpc/demo/dir/Makefile @@ -0,0 +1,26 @@ +# +# @(#)Makefile	2.1 88/08/02 4.0 RPCSRC +# +BIN = dir_svc rls +GEN = dir_clnt.c dir_svc.c dir_xdr.c dir.h +LIB = -lrpclib +RPCCOM = rpcgen + +all: $(BIN) + +$(GEN): dir.x +	$(RPCCOM) dir.x + +dir_svc: dir_proc.o dir_svc.o dir_xdr.o +	$(CC) -o $@ dir_proc.o dir_svc.o dir_xdr.o $(LIB) + +rls: rls.o dir_clnt.o dir_xdr.o +	$(CC) -o $@ rls.o dir_clnt.o dir_xdr.o $(LIB) + +rls.o: rls.c dir.h + +dir_proc.o: dir_proc.c dir.h + +clean cleanup: +	rm -f $(GEN) *.o $(BIN) + diff --git a/lib/librpc/demo/dir/dir.x b/lib/librpc/demo/dir/dir.x new file mode 100644 index 000000000000..db4283cbfe00 --- /dev/null +++ b/lib/librpc/demo/dir/dir.x @@ -0,0 +1,37 @@ +/* @(#)dir.x	2.1 88/08/02 4.0 RPCSRC */ +/* + * dir.x: Remote directory listing protocol + */ +const MAXNAMELEN = 255;		/* maximum length of a directory entry */ + +typedef string nametype<MAXNAMELEN>;	/* a directory entry */ + +typedef struct namenode *namelist;	/* a link in the listing */ + +/* + * A node in the directory listing + */ +struct namenode { +	nametype name;		/* name of directory entry */ +	namelist next;		/* next entry */ +}; + +/* + * The result of a READDIR operation. + */ +union readdir_res switch (int errno) { +case 0: +	namelist list;	/* no error: return directory listing */ +default: +	void;		/* error occurred: nothing else to return */ +}; + +/* + * The directory program definition + */ +program DIRPROG { +	version DIRVERS { +		readdir_res +		READDIR(nametype) = 1; +	} = 1; +} = 76; diff --git a/lib/librpc/demo/dir/dir_proc.c b/lib/librpc/demo/dir/dir_proc.c new file mode 100644 index 000000000000..9f7522a92715 --- /dev/null +++ b/lib/librpc/demo/dir/dir_proc.c @@ -0,0 +1,55 @@ +/* @(#)dir_proc.c	2.1 88/08/02 4.0 RPCSRC */ +/* + * dir_proc.c: remote readdir implementation + */ +#include <rpc/rpc.h> +#include <sys/dir.h> +#include "dir.h" + +extern int errno; +extern char *malloc(); +extern char *strcpy(); + +readdir_res * +readdir_1(dirname) +	nametype *dirname; +{ +	DIR *dirp; +	struct direct *d; +	namelist nl; +	namelist *nlp; +	static readdir_res res; /* must be static! */ +	 +	/* +	 * Open directory +	 */ +	dirp = opendir(*dirname); +	if (dirp == NULL) { +		res.errno = errno; +		return (&res); +	} + +	/* +	 * Free previous result +	 */ +	xdr_free(xdr_readdir_res, &res); + +	/* +	 * Collect directory entries +	 */ +	nlp = &res.readdir_res_u.list; +	while (d = readdir(dirp)) { +		nl = *nlp = (namenode *) malloc(sizeof(namenode)); +		nl->name = malloc(strlen(d->d_name)+1); +		strcpy(nl->name, d->d_name); +		nlp = &nl->next; +	} +	*nlp = NULL; + +	/* +	 * Return the result +	 */ +	res.errno = 0; +	closedir(dirp); +	return (&res); +} diff --git a/lib/librpc/demo/dir/rls.c b/lib/librpc/demo/dir/rls.c new file mode 100644 index 000000000000..4f2d473674e4 --- /dev/null +++ b/lib/librpc/demo/dir/rls.c @@ -0,0 +1,81 @@ +/* @(#)rls.c	2.2 88/08/12 4.0 RPCSRC */ +/* + * rls.c: Remote directory listing client + */ +#include <stdio.h> +#include <rpc/rpc.h>		/* always need this */ +#include "dir.h"		/* need this too: will be generated by rpcgen*/ + +extern int errno; + +main(argc, argv) +	int argc; +	char *argv[]; +{ +	CLIENT *cl; +	char *server; +	char *dir; +	readdir_res *result; +	namelist nl; +	 + +	if (argc != 3) { +		fprintf(stderr, "usage: %s host directory\n", argv[0]); +		exit(1); +	} + +	/* +	 * Remember what our command line arguments refer to +	 */ +	server = argv[1]; +	dir = argv[2]; + +	/* +	 * Create client "handle" used for calling DIRPROG on the +	 * server designated on the command line. We tell the rpc package +	 * to use the "tcp" protocol when contacting the server. +	 */ +	cl = clnt_create(server, DIRPROG, DIRVERS, "tcp"); +	if (cl == NULL) { +		/* +		 * Couldn't establish connection with server. +		 * Print error message and die. +		 */ +		clnt_pcreateerror(server); +		exit(1); +	} +	 +	/* +	 * Call the remote procedure "readdir" on the server +	 */ +	result = readdir_1(&dir, cl); +	if (result == NULL) { +		/* +		 * An error occurred while calling the server.  +	 	 * Print error message and die. +		 */ +		clnt_perror(cl, server); +		exit(1); +	} + +	/* +	 * Okay, we successfully called the remote procedure. +	 */ +	if (result->errno != 0) { +		/* +		 * A remote system error occurred. +		 * Print error message and die. +		 */ +		errno = result->errno; +		perror(dir); +		exit(1); +	} + +	/* +	 * Successfuly got a directory listing. +	 * Print it out. +	 */ +	for (nl = result->readdir_res_u.list; nl != NULL; nl = nl->next) { +		printf("%s\n", nl->name); +	} +} diff --git a/lib/librpc/demo/msg/Makefile b/lib/librpc/demo/msg/Makefile new file mode 100644 index 000000000000..2f3f5ddf1655 --- /dev/null +++ b/lib/librpc/demo/msg/Makefile @@ -0,0 +1,36 @@ +# +# @(#)Makefile	2.1 88/08/11 4.0 RPCSRC +# +BIN = printmsg msg_svc rprintmsg +GEN = msg_clnt.c msg_svc.c msg.h +LIB = -lrpclib +RPCCOM = rpcgen + +all: $(BIN) + +# +# This is the non-networked version of the program +# +printmsg: printmsg.o +	$(CC) -o $@ printmsg.o + +# +# note: no xdr routines are generated here, due this service's +#       use of basic data types. +# +$(GEN): msg.x +	$(RPCCOM) msg.x + +msg_svc: msg_proc.o msg_svc.o +	$(CC) -o $@ msg_proc.o msg_svc.o $(LIB) + +rprintmsg: rprintmsg.o msg_clnt.o +	$(CC) -o $@ rprintmsg.o msg_clnt.o $(LIB) + +rprintmsg.o: rprintmsg.c msg.h + +msg_proc.o: msg_proc.c msg.h + +clean cleanup: +	rm -f $(GEN) *.o $(BIN) + diff --git a/lib/librpc/demo/msg/msg.x b/lib/librpc/demo/msg/msg.x new file mode 100644 index 000000000000..d3113520d822 --- /dev/null +++ b/lib/librpc/demo/msg/msg.x @@ -0,0 +1,9 @@ +/* @(#)msg.x	2.1 88/08/11 4.0 RPCSRC */ +/* + * msg.x: Remote message printing protocol + */ +program MESSAGEPROG { +	version MESSAGEVERS { +		int PRINTMESSAGE(string) = 1; +	} = 1; +} = 99; diff --git a/lib/librpc/demo/msg/msg_proc.c b/lib/librpc/demo/msg/msg_proc.c new file mode 100644 index 000000000000..80e5d959aa7f --- /dev/null +++ b/lib/librpc/demo/msg/msg_proc.c @@ -0,0 +1,28 @@ +/* @(#)msg_proc.c	2.1 88/08/11 4.0 RPCSRC */ +/* + * msg_proc.c: implementation of the remote procedure "printmessage" + */ +#include <stdio.h> +#include <rpc/rpc.h>	/* always need this here */ +#include "msg.h"	/* need this too: msg.h will be generated by rpcgen */ + +/* + * Remote verson of "printmessage" + */ +int *		 +printmessage_1(msg) +	char **msg;	 +{ +	static int result; /* must be static! */ +	FILE *f; + +	f = fopen("/dev/console", "w"); +	if (f == NULL) { +		result = 0; +		return (&result); +	} +	fprintf(f, "%s\n", *msg); +	fclose(f); +	result = 1; +	return (&result); +} diff --git a/lib/librpc/demo/msg/printmsg.c b/lib/librpc/demo/msg/printmsg.c new file mode 100644 index 000000000000..dde55dd86709 --- /dev/null +++ b/lib/librpc/demo/msg/printmsg.c @@ -0,0 +1,43 @@ +/* @(#)printmsg.c	2.1 88/08/11 4.0 RPCSRC */ +/* + * printmsg.c: print a message on the console + */ +#include <stdio.h> + +main(argc, argv) +	int argc; +	char *argv[]; +{ +	char *message; + +	if (argc < 2) { +		fprintf(stderr, "usage: %s <message>\n", argv[0]); +		exit(1); +	} +	message = argv[1]; + +	if (!printmessage(message)) { +		fprintf(stderr, "%s: sorry, couldn't print your message\n", +			argv[0]); +		exit(1); +	}  +	printf("Message delivered!\n"); +} + +/* + * Print a message to the console. + * Return a boolean indicating whether the message was actually printed. + */ +printmessage(msg) +	char *msg; +{ +	FILE *f; + +	f = fopen("/dev/console", "w"); +	if (f == NULL) { +		return (0); +	} +	fprintf(f, "%s\n", msg); +	fclose(f); +	return(1); +} diff --git a/lib/librpc/demo/msg/rprintmsg.c b/lib/librpc/demo/msg/rprintmsg.c new file mode 100644 index 000000000000..b9cb1e361706 --- /dev/null +++ b/lib/librpc/demo/msg/rprintmsg.c @@ -0,0 +1,74 @@ +/* @(#)rprintmsg.c	2.1 88/08/11 4.0 RPCSRC */ +/* + * rprintmsg.c: remote version of "printmsg.c" + */ +#include <stdio.h> +#include <rpc/rpc.h>		/* always need this */ +#include "msg.h"		/* need this too: will be generated by rpcgen*/ + +main(argc, argv) +	int argc; +	char *argv[]; +{ +	CLIENT *cl; +	int *result; +	char *server; +	char *message; + +	if (argc < 3) { +		fprintf(stderr, "usage: %s host message\n", argv[0]); +		exit(1); +	} + +	/* +	 * Remember what our command line arguments refer to +	 */ +	server = argv[1]; +	message = argv[2]; + +	/* +	 * Create client "handle" used for calling MESSAGEPROG on the +	 * server designated on the command line. We tell the rpc package +	 * to use the "tcp" protocol when contacting the server. +	 */ +	cl = clnt_create(server, MESSAGEPROG, MESSAGEVERS, "tcp"); +	if (cl == NULL) { +		/* +		 * Couldn't establish connection with server. +		 * Print error message and die. +		 */ +		clnt_pcreateerror(server); +		exit(1); +	} +	 +	/* +	 * Call the remote procedure "printmessage" on the server +	 */ +	result = printmessage_1(&message, cl); +	if (result == NULL) { +		/* +		 * An error occurred while calling the server.  +	 	 * Print error message and die. +		 */ +		clnt_perror(cl, server); +		exit(1); +	} + +	/* +	 * Okay, we successfully called the remote procedure. +	 */ +	if (*result == 0) { +		/* +		 * Server was unable to print our message.  +		 * Print error message and die. +		 */ +		fprintf(stderr, "%s: sorry, %s couldn't print your message\n",  +			argv[0], server);	 +		exit(1); +	}  + +	/* +	 * The message got printed on the server's console +	 */ +	printf("Message delivered to %s!\n", server); +} diff --git a/lib/librpc/demo/sort/Makefile b/lib/librpc/demo/sort/Makefile new file mode 100644 index 000000000000..07627fafbe39 --- /dev/null +++ b/lib/librpc/demo/sort/Makefile @@ -0,0 +1,36 @@ +# +# @(#)Makefile	2.1 88/08/11 4.0 RPCSRC +# + +BIN =  rsort sort_svc +GEN = sort_clnt.c sort_svc.c sort_xdr.c sort.h +LIB = -lrpclib +RPCCOM = rpcgen + +all: $(BIN) + +rsort: rsort.o sort_clnt.o sort_xdr.o +	$(CC) $(LDFLAGS) -o $@ rsort.o sort_clnt.o sort_xdr.o $(LIB) + +rsort.o: rsort.c sort.h + +sort_clnt.c: +	$(RPCCOM) -l sort.x >$@ + +sort_svc: sort_proc.o sort_svc.o sort_xdr.o +	$(CC) $(LDFLAGS) -o $@ sort_proc.o sort_svc.o sort_xdr.o $(LIB) + +sort_proc.o: sort_proc.c sort.h + +sort_svc.c: +	$(RPCCOM) -s udp sort.x >$@ + +sort_xdr.c: +	$(RPCCOM) -c sort.x >$@ + +sort.h: +	$(RPCCOM) -h sort.x >$@ + +clean cleanup: +	rm -f $(GEN) *.o $(BIN) + diff --git a/lib/librpc/demo/sort/rsort.c b/lib/librpc/demo/sort/rsort.c new file mode 100644 index 000000000000..5c05ad7f42cc --- /dev/null +++ b/lib/librpc/demo/sort/rsort.c @@ -0,0 +1,43 @@ +/* @(#)rsort.c	2.1 88/08/11 4.0 RPCSRC */ +/* + * rsort.c + * Client side application which sorts argc, argv. + */ +#include <stdio.h> +#include <rpc/rpc.h> +#include "sort.h" + +main(argc, argv) +	int argc; +	char **argv; +{ +	char *machinename; +	struct sortstrings args, res; +	int i; + +	if (argc < 3) { +		fprintf(stderr, "usage: %s machinename [s1 ...]\n", argv[0]); +		exit(1); +	} +	machinename = argv[1]; +	args.ss.ss_len = argc - 2;     /* substract off progname, machinename */ +	args.ss.ss_val = &argv[2]; +	res.ss.ss_val = (char **)NULL; + +	if ((i = callrpc(machinename, SORTPROG, SORTVERS, SORT, +	    xdr_sortstrings, &args, xdr_sortstrings, &res))) +	{ +	    fprintf(stderr, "%s: call to sort service failed. ", argv[0]); +	    clnt_perrno(i); +	    fprintf(stderr, "\n"); +	    exit(1); +	} + +	for (i = 0; i < res.ss.ss_len; i++) { +		printf("%s\n", res.ss.ss_val[i]); +	} + +	/* should free res here */ +	exit(0); +} + diff --git a/lib/librpc/demo/sort/sort.x b/lib/librpc/demo/sort/sort.x new file mode 100644 index 000000000000..629110cdf33a --- /dev/null +++ b/lib/librpc/demo/sort/sort.x @@ -0,0 +1,19 @@ +/* @(#)sort.x	2.1 88/08/11 4.0 RPCSRC */ +/* + * The sort procedure receives an array of strings and returns an array + * of strings.  This toy service handles a maximum of 64 strings. + */ +const MAXSORTSIZE  = 64; +const MAXSTRINGLEN = 64; + +typedef	string  str<MAXSTRINGLEN>;  /* the string itself */ + +struct sortstrings { +    str ss<MAXSORTSIZE>; +}; + +program SORTPROG { +    version SORTVERS { +        sortstrings SORT(sortstrings) = 1; +    } = 1; +} = 22855; diff --git a/lib/librpc/demo/sort/sort_proc.c b/lib/librpc/demo/sort/sort_proc.c new file mode 100644 index 000000000000..5538faf7ea03 --- /dev/null +++ b/lib/librpc/demo/sort/sort_proc.c @@ -0,0 +1,27 @@ +/* @(#)sort_proc.c	2.1 88/08/11 4.0 RPCSRC */ +#include <rpc/rpc.h> +#include "sort.h" + +static int +comparestrings(sp1, sp2) +    char **sp1, **sp2; +{ +    return (strcmp(*sp1, *sp2)); +} + +struct sortstrings * +sort_1(ssp) +    struct sortstrings *ssp; +{ +    static struct sortstrings ss_res; + +    if (ss_res.ss.ss_val != (str *)NULL) +        free(ss_res.ss.ss_val); + +    qsort(ssp->ss.ss_val, ssp->ss.ss_len, sizeof (char *), comparestrings); +    ss_res.ss.ss_len = ssp->ss.ss_len; +    ss_res.ss.ss_val = (str *)malloc(ssp->ss.ss_len * sizeof(str *)); +    bcopy(ssp->ss.ss_val, ss_res.ss.ss_val, +        ssp->ss.ss_len * sizeof(str *)); +    return(&ss_res); +} diff --git a/lib/librpc/doc/Makefile b/lib/librpc/doc/Makefile new file mode 100644 index 000000000000..db819a097bb2 --- /dev/null +++ b/lib/librpc/doc/Makefile @@ -0,0 +1,84 @@ +# +# @(#)Makefile	2.1 88/08/04 4.0 RPCSRC +# +# +#   The targets all.nroff and all.troff will make monolithic documents +#   with nroff and troff, respectively.  The other *.nroff and *.troff +#   targets will make individual documents +# +TROFF=	ditroff +TOPTS=  -t +NROFF=	nroff +NOPTS= +PIC=	pic +TBL=	tbl +EQN=	eqn + +SRC=	 rpc.prog.ms rpcgen.ms xdr.nts.ms xdr.rfc.ms rpc.rfc.ms nfs.rfc.ms + +all default: all.nroff + +install:	all.nroff +	@echo "Nothing installed." + +all.nroff:	${SRC} +	${TBL} ${SRC} | ${EQN} | ${NROFF} ${NOPTS} -ms >all.nroff + +all.troff:	${SRC} +	${TBL} ${SRC} | ${PIC} | ${EQN} | ${TROFF} ${TOPTS} -ms >all.troff + +# + +rpc.prog.nroff: rpc.prog.ms +	${TBL} rpc.prog.ms | ${NROFF} ${NOPTS} -ms >rpc.prog.nroff + +rpc.prog.troff:	rpc.prog.ms +	${TBL} rpc.prog.ms | ${PIC} | ${TROFF} ${TOPTS} -ms >rpc.prog.troff + +# + +rpcgen.troff:	rpcgen.ms +	${TBL} rpcgen.ms | ${TROFF} ${TOPTS} -ms >rpcgen.troff + +rpcgen.nroff:	rpcgen.ms +	${TBL} rpcgen.ms | ${NROFF} ${NOPTS} -ms >rpcgen.nroff + +# + +xdr.nts.troff: xdr.nts.ms +	${TBL} xdr.nts.ms | ${EQN} | ${TROFF} ${TOPTS} -ms >xdr.nts.troff + +xdr.nts.nroff: xdr.nts.ms +	${TBL} xdr.nts.ms | ${EQN} | ${NROFF} ${NOPTS} -ms >xdr.nts.nroff + +# + +xdr.rfc.troff: xdr.rfc.ms +	${TBL} xdr.rfc.ms | ${TROFF} ${TOPTS} -ms >xdr.rfc.troff + +xdr.rfc.nroff: xdr.rfc.ms +	${TBL} xdr.rfc.ms | ${NROFF} ${NOPTS} -ms >xdr.rfc.nroff + +# + +rpc.rfc.troff: rpc.rfc.ms +	${TBL} rpc.rfc.ms | ${TROFF} ${TOPTS} -ms >rpc.rfc.troff + +rpc.rfc.nroff: rpc.rfc.ms +	${TBL} rpc.rfc.ms | ${NROFF} ${NOPTS} -ms >rpc.rfc.nroff + +# + +nfs.rfc.troff: nfs.rfc.ms +	${TBL} nfs.rfc.ms | ${TROFF} ${TOPTS} -ms >nfs.rfc.troff + +nfs.rfc.nroff: nfs.rfc.ms +	${TBL} nfs.rfc.ms | ${NROFF} ${NOPTS} -ms >nfs.rfc.nroff + +clean: +	rm -f *.nroff *.troff + +spell:	${SRC} +	@for i in ${SRC}; do \ +		echo $$i; spell $$i | sort | comm -23 - spell.ok > $$i.spell; \ +	done diff --git a/lib/librpc/doc/nfs.rfc.ms b/lib/librpc/doc/nfs.rfc.ms new file mode 100644 index 000000000000..0c9a8995b5c7 --- /dev/null +++ b/lib/librpc/doc/nfs.rfc.ms @@ -0,0 +1,1372 @@ +.\" +.\" Must use  --  tbl  --  with this one +.\" +.\" @(#)nfs.rfc.ms	2.2 88/08/05 4.0 RPCSRC +.de BT +.if \\n%=1 .tl ''- % -'' +.. +.ND +.\" prevent excess underlining in nroff +.if n .fp 2 R +.OH 'Network File System: Version 2 Protocol Specification''Page %' +.EH 'Page %''Network File System: Version 2 Protocol Specification' +.if \\n%=1 .bp +.SH +\&Network File System: Version 2 Protocol Specification +.IX NFS "" "" "" PAGE MAJOR +.IX "Network File System" "" "" "" PAGE MAJOR +.IX NFS "version-2 protocol specification" +.IX "Network File System" "version-2 protocol specification" +.LP +.NH 0 +\&Status of this Standard +.LP +Note: This document specifies a protocol that Sun Microsystems, Inc., +and others are using.  It specifies it in standard ARPA RFC form. +.NH 1 +\&Introduction +.IX NFS introduction +.LP +The Sun Network Filesystem (NFS) protocol provides transparent remote  +access to shared filesystems over local area networks.  The NFS  +protocol is designed to be machine, operating system, network architecture,  +and transport protocol independent.  This independence is  +achieved through the use of Remote Procedure Call (RPC) primitives  +built on top of an External Data Representation (XDR).  Implementations +exist for a variety of machines, from personal computers to +supercomputers. +.LP +The supporting mount protocol allows the server to hand out remote +access privileges to a restricted set of clients.  It performs the +operating system-specific functions that allow, for example, to +attach remote directory trees to some local file system. +.NH 2 +\&Remote Procedure Call +.IX "Remote Procedure Call" +.LP +Sun's remote procedure call specification provides a procedure- +oriented interface to remote services.  Each server supplies a +program that is a set of procedures.  NFS is one such "program". +The combination of host address, program number, and procedure +number specifies one remote service procedure.  RPC does not depend +on services provided by specific protocols, so it can be used with +any underlying transport protocol.  See the +.I "Remote Procedure Calls: Protocol Specification" +chapter of this manual. +.NH 2 +\&External Data Representation +.IX "External Data Representation" +.LP +The External Data Representation (XDR) standard provides a common +way of representing a set of data types over a network.   +The NFS +Protocol Specification is written using the RPC data description +language.   +For more information, see the +.I " External Data Representation Standard: Protocol Specification."   +Sun provides implementations of XDR and +RPC,  but NFS does not require their use.  Any software that +provides equivalent functionality can be used, and if the encoding +is exactly the same it can interoperate with other implementations +of NFS. +.NH 2 +\&Stateless Servers +.IX "stateless servers" +.IX servers stateless +.LP +The NFS protocol is stateless.  That is, a server does not need to +maintain any extra state information about any of its clients in +order to function correctly.  Stateless servers have a distinct +advantage over stateful servers in the event of a failure.  With +stateless servers, a client need only retry a request until the +server responds; it does not even need to know that the server has +crashed, or the network temporarily went down.  The client of a +stateful server, on the other hand, needs to either detect a server +crash and rebuild the server's state when it comes back up, or +cause client operations to fail. +.LP +This may not sound like an important issue, but it affects the +protocol in some unexpected ways.  We feel that it is worth a bit +of extra complexity in the protocol to be able to write very simple +servers that do not require fancy crash recovery. +.LP +On the other hand, NFS deals with objects such as files and +directories that inherently have state -- what good would a file be +if it did not keep its contents intact?  The goal is to not +introduce any extra state in the protocol itself.  Another way to +simplify recovery is by making operations "idempotent" whenever +possible (so that they can potentially be repeated). +.NH 1 +\&NFS Protocol Definition +.IX NFS "protocol definition" +.IX NFS protocol +.LP +Servers have been known to change over time, and so can the +protocol that they use. So RPC provides a version number with each +RPC request. This RFC describes version two of the NFS protocol. +Even in the second version, there are various obsolete procedures +and parameters, which will be removed in later versions. An RFC +for version three of the NFS protocol is currently under +preparation. +.NH 2 +\&File System Model +.IX filesystem model +.LP +NFS assumes a file system that is hierarchical, with directories as +all but the bottom-level files.  Each entry in a directory (file, +directory, device, etc.)  has a string name.  Different operating +systems may have restrictions on the depth of the tree or the names +used, as well as using different syntax to represent the "pathname", +which is the concatenation of all the "components" (directory and +file names) in the name.  A "file system" is a tree on a single +server (usually a single disk or physical partition) with a specified +"root".  Some operating systems provide a "mount" operation to make +all file systems appear as a single tree, while others maintain a +"forest" of file systems.  Files are unstructured streams of +uninterpreted bytes.  Version 3 of NFS uses a slightly more general +file system model. +.LP +NFS looks up one component of a pathname at a time.  It may not be +obvious why it does not just take the whole pathname, traipse down +the directories, and return a file handle when it is done.  There are +several good reasons not to do this.  First, pathnames need +separators between the directory components, and different operating +systems use different separators.  We could define a Network Standard +Pathname Representation, but then every pathname would have to be +parsed and converted at each end.  Other issues are discussed in +\fINFS Implementation Issues\fP below. +.LP +Although files and directories are similar objects in many ways, +different procedures are used to read directories and files.  This +provides a network standard format for representing directories.  The +same argument as above could have been used to justify a procedure +that returns only one directory entry per call.  The problem is +efficiency.  Directories can contain many entries, and a remote call +to return each would be just too slow. +.NH 2 +\&RPC Information +.IX NFS "RPC information" +.IP \fIAuthentication\fP +The   NFS  service uses  +.I AUTH_UNIX , +.I AUTH_DES , +or  +.I AUTH_SHORT  +style +authentication, except in  the  NULL procedure where    +.I AUTH_NONE  +is also allowed. +.IP "\fITransport Protocols\fP" +NFS currently is supported on UDP/IP only.   +.IP "\fIPort Number\fP" +The NFS protocol currently uses the UDP port number 2049.  This is +not an officially assigned port, so  later versions of the protocol +use the \*QPortmapping\*U facility of RPC. +.NH 2 +\&Sizes of XDR Structures +.IX "XDR structure sizes" +.LP +These are the sizes, given in decimal bytes, of various XDR +structures used in the protocol: +.DS +/* \fIThe maximum number of bytes of data in a READ or WRITE request\fP  */ +const MAXDATA = 8192; + +/* \fIThe maximum number of bytes in a pathname argument\fP */ +const MAXPATHLEN = 1024; + +/* \fIThe maximum number of bytes in a file name argument\fP */ +const MAXNAMLEN = 255; + +/* \fIThe size in bytes of the opaque "cookie" passed by READDIR\fP */ +const COOKIESIZE  = 4; + +/* \fIThe size in bytes of the opaque file handle\fP */ +const FHSIZE = 32; +.DE +.NH 2 +\&Basic Data Types +.IX "NFS data types" +.IX NFS "basic data types" +.LP +The following XDR  definitions are basic  structures and types used +in other structures described further on. +.KS +.NH 3 +\&stat +.IX "NFS data types" stat "" \fIstat\fP +.DS +enum stat { +	NFS_OK = 0, +	NFSERR_PERM=1, +	NFSERR_NOENT=2, +	NFSERR_IO=5, +	NFSERR_NXIO=6, +	NFSERR_ACCES=13, +	NFSERR_EXIST=17, +	NFSERR_NODEV=19, +	NFSERR_NOTDIR=20, +	NFSERR_ISDIR=21, +	NFSERR_FBIG=27, +	NFSERR_NOSPC=28, +	NFSERR_ROFS=30, +	NFSERR_NAMETOOLONG=63, +	NFSERR_NOTEMPTY=66, +	NFSERR_DQUOT=69, +	NFSERR_STALE=70, +	NFSERR_WFLUSH=99 +}; +.DE +.KE +.LP +The  +.I stat  +type  is returned with every  procedure's  results.   A +value of  +.I NFS_OK  +indicates that the  call completed successfully and +the  results are  valid.  The  other  values indicate  some kind of +error  occurred on the  server  side  during the servicing   of the +procedure.  The error values are derived from UNIX error numbers. +.IP \fBNFSERR_PERM\fP: +Not owner.  The caller does not have correct ownership +to perform the requested operation. +.IP \fBNFSERR_NOENT\fP: +No such file or directory.    The file or directory +specified does not exist. +.IP \fBNFSERR_IO\fP: +Some sort of hard  error occurred when the operation was +in progress.  This could be a disk error, for example. +.IP \fBNFSERR_NXIO\fP: +No such device or address. +.IP \fBNFSERR_ACCES\fP: +Permission  denied.  The  caller does  not  have the +correct permission to perform the requested operation. +.IP \fBNFSERR_EXIST\fP: +File exists.  The file specified already exists. +.IP \fBNFSERR_NODEV\fP: +No such device. +.IP \fBNFSERR_NOTDIR\fP: +Not   a  directory.    The  caller  specified   a +non-directory in a directory operation. +.IP \fBNFSERR_ISDIR\fP: +Is a directory.  The caller specified  a directory in +a non- directory operation. +.IP \fBNFSERR_FBIG\fP: +File too large.   The  operation caused a file to grow +beyond the server's limit. +.IP \fBNFSERR_NOSPC\fP: +No space left on  device.   The operation caused the +server's filesystem to reach its limit. +.IP \fBNFSERR_ROFS\fP: +Read-only filesystem.  Write attempted on a read-only filesystem. +.IP \fBNFSERR_NAMETOOLONG\fP: +File name   too   long.  The file  name  in  an operation was too long. +.IP \fBNFSERR_NOTEMPTY\fP: +Directory   not empty.  Attempted  to   remove  a +directory that was not empty. +.IP \fBNFSERR_DQUOT\fP: +Disk quota exceeded.  The client's disk  quota on the +server has been exceeded. +.IP \fBNFSERR_STALE\fP: +The  "fhandle" given in   the arguments was invalid. +That is, the file referred to by that file handle no longer exists, +or access to it has been revoked. +.IP \fBNFSERR_WFLUSH\fP: +The server's  write cache  used  in the +.I WRITECACHE  +call got flushed to disk. +.LP +.KS +.NH 3 +\&ftype +.IX "NFS data types" ftype "" \fIftype\fP +.DS +enum ftype { +	NFNON = 0, +	NFREG = 1, +	NFDIR = 2, +	NFBLK = 3, +	NFCHR = 4, +	NFLNK = 5 +}; +.DE +.KE +The enumeration +.I ftype  +gives the type of a file.  The type  +.I NFNON  +indicates a non-file, +.I NFREG  +is a regular file,  +.I NFDIR  +is a directory, +.I NFBLK  +is a block-special device,  +.I NFCHR  +is a character-special device, and +.I NFLNK  +is a symbolic link. +.KS +.NH 3 +\&fhandle +.IX "NFS data types" fhandle "" \fIfhandle\fP +.DS +typedef opaque fhandle[FHSIZE]; +.DE +.KE +The +.I fhandle  +is the file handle passed between the server and the client.   +All file operations are done using file handles to refer to a file or  +directory.  The file handle can contain whatever information the server +needs to distinguish an individual file. +.KS +.NH 3 +\&timeval +.IX "NFS data types" timeval "" \fItimeval\fP +.DS +struct timeval { +	unsigned int seconds; +	unsigned int useconds; +}; +.DE +.KE +The  +.I timeval +structure is the number of seconds and microseconds  +since midnight January 1, 1970, Greenwich Mean Time.  It is used to  +pass time and date information. +.KS +.NH 3 +\&fattr +.IX "NFS data types" fattr "" \fIfattr\fP +.DS +struct fattr { +	ftype        type; +	unsigned int mode; +	unsigned int nlink; +	unsigned int uid; +	unsigned int gid; +	unsigned int size; +	unsigned int blocksize; +	unsigned int rdev; +	unsigned int blocks; +	unsigned int fsid; +	unsigned int fileid; +	timeval      atime; +	timeval      mtime; +	timeval      ctime; +}; +.DE +.KE +The +.I fattr  +structure contains the attributes of a file; "type" is the type of +the file; "nlink" is the number of hard links to the file (the number +of different names for the same file); "uid" is the user +identification number of the owner of the file; "gid" is the group +identification number of the group of the file; "size" is the size in +bytes of the file; "blocksize" is the size in bytes of a block of the +file; "rdev" is the device number of the file if it is type +.I NFCHR  +or +.I NFBLK ; +"blocks" is the number of blocks the file takes up on disk; "fsid" is +the file system identifier for the filesystem containing the file; +"fileid" is a number that uniquely identifies the file within its +filesystem; "atime" is the time when the file was last accessed for +either read or write; "mtime" is the time when the file data was last +modified (written); and "ctime" is the time when the status of the +file was last changed.  Writing to the file also changes "ctime" if +the size of the file changes. +.LP +"mode" is the access mode encoded as a set of bits.  Notice that the +file type is specified both in the mode bits and in the file type. +This is really a bug in the protocol and will be fixed in future +versions.  The descriptions given below specify the bit positions +using octal numbers. +.TS +box tab (&) ; +cfI cfI +lfL l . +Bit&Description +_ +0040000&This is a directory; "type" field should be NFDIR. +0020000&This is a character special file; "type" field should be NFCHR.  +0060000&This is a block special file; "type" field should be NFBLK.  +0100000&This is a regular file; "type" field should be NFREG. +0120000&This is a symbolic link file;  "type" field should be NFLNK.  +0140000&This is a named socket; "type" field should be NFNON. +0004000&Set user id on execution. +0002000&Set group id on execution. +0001000&Save swapped text even after use. +0000400&Read permission for owner. +0000200&Write permission for owner. +0000100&Execute and search permission for owner. +0000040&Read permission for group. +0000020&Write permission for group. +0000010&Execute and search permission for group. +0000004&Read permission for others. +0000002&Write permission for others. +0000001&Execute and search permission for others. +.TE +.KS +Notes: +.IP  +The bits are  the same as the mode   bits returned  by  the +.I stat(2)  +system call in the UNIX system.  The file  type is  specified  both in +the mode  bits  and in  the file type.   This   is fixed  in future +versions. +.IP +The "rdev" field in the attributes structure is an operating system +specific device specifier.  It  will be  removed and generalized in +the next revision of the protocol. +.KE +.LP +.KS +.NH 3 +\&sattr +.IX "NFS data types" sattr "" \fIsattr\fP +.DS +struct sattr { +	unsigned int mode; +	unsigned int uid; +	unsigned int gid; +	unsigned int size; +	timeval      atime; +	timeval      mtime; +}; +.DE +.KE +The  +.I sattr +structure contains the file attributes which can be set +from the client.  The fields are the same as for   +.I fattr  +above.  A "size" of zero  means the file should be  truncated. +A value of -1 indicates a field that should be ignored. +.LP +.KS +.NH 3 +\&filename +.IX "NFS data types" filename "" \fIfilename\fP +.DS +typedef string filename<MAXNAMLEN>; +.DE +.KE +The type +.I filename  +is used for  passing file names  or  pathname components. +.LP +.KS +.NH 3 +\&path +.IX "NFS data types" path "" \fIpath\fP +.DS +typedef string path<MAXPATHLEN>; +.DE +.KE +The type +.I path  +is a pathname.  The server considers it as a string +with no internal structure,  but to the client  it is the name of a +node in a filesystem tree. +.LP +.KS +.NH 3 +\&attrstat +.IX "NFS data types" attrstat "" \fIattrstat\fP +.DS +union attrstat switch (stat status) { +	case NFS_OK: +		fattr attributes; +	default: +		void; +}; +.DE +.KE +The  +.I attrstat  +structure is a common procedure result.  It contains +a  "status" and,  if  the call   succeeded,   it also contains  the +attributes of the file on which the operation was done. +.LP +.KS +.NH 3 +\&diropargs +.IX "NFS data types" diropargs "" \fIdiropargs\fP +.DS +struct diropargs { +	fhandle  dir; +	filename name; +}; +.DE +.KE +The   +.I diropargs  +structure is used  in  directory  operations.  The +"fhandle" "dir" is the directory in  which to find the file "name". +A directory operation is one in which the directory is affected. +.LP +.KS +.NH 3 +\&diropres +.IX "NFS data types" diropres "" \fIdiropres\fP +.DS +union diropres switch (stat status) { +	case NFS_OK: +		struct { +			fhandle file; +			fattr   attributes; +		} diropok; +	default: +		void; +}; +.DE +.KE +The results of a directory operation  are returned  in a  +.I diropres  +structure.  If the call succeeded, a new file handle "file" and the +"attributes" associated with that file are  returned along with the +"status". +.NH 2 +\&Server Procedures +.IX "NFS server procedures" "" "" "" PAGE MAJOR +.LP +The  protocol definition  is given as   a  set  of  procedures with +arguments  and results defined using the   RPC  language.   A brief +description of the function of each procedure should provide enough +information to allow implementation. +.LP +All of  the procedures  in   the NFS  protocol  are assumed  to  be +synchronous.   When a procedure  returns to the  client, the client +can assume that the operation has completed and any data associated +with the request is  now on stable storage.  For  example, a client +.I WRITE  +request   may  cause  the   server  to  update  data  blocks, +filesystem information blocks (such as indirect  blocks),  and file +attribute  information (size  and  modify  times).  When  the  +.I WRITE  +returns to the client, it can assume  that the write  is safe, even +in case of  a server  crash, and  it can discard the  data written. +This is a very important part  of the statelessness  of the server. +If the server waited to flush data from remote requests, the client +would have to  save those requests so that  it could resend them in +case of a server crash. +.ie t .DS +.el .DS L + +.ft I +/* +* Remote file service routines +*/ +.ft CW +program NFS_PROGRAM { +	version NFS_VERSION { +		void        NFSPROC_NULL(void)              = 0; +		attrstat    NFSPROC_GETATTR(fhandle)        = 1; +		attrstat    NFSPROC_SETATTR(sattrargs)      = 2; +		void        NFSPROC_ROOT(void)              = 3; +		diropres    NFSPROC_LOOKUP(diropargs)       = 4; +		readlinkres NFSPROC_READLINK(fhandle)       = 5; +		readres     NFSPROC_READ(readargs)          = 6; +		void        NFSPROC_WRITECACHE(void)        = 7; +		attrstat    NFSPROC_WRITE(writeargs)        = 8; +		diropres    NFSPROC_CREATE(createargs)      = 9; +		stat        NFSPROC_REMOVE(diropargs)       = 10; +		stat        NFSPROC_RENAME(renameargs)      = 11; +		stat        NFSPROC_LINK(linkargs)          = 12; +		stat        NFSPROC_SYMLINK(symlinkargs)    = 13; +		diropres    NFSPROC_MKDIR(createargs)       = 14; +		stat        NFSPROC_RMDIR(diropargs)        = 15; +		readdirres  NFSPROC_READDIR(readdirargs)    = 16; +		statfsres   NFSPROC_STATFS(fhandle)         = 17; +	} = 2; +} = 100003; +.DE +.KS +.NH 3 +\&Do Nothing +.IX "NFS server procedures" NFSPROC_NULL() "" \fINFSPROC_NULL()\fP +.DS +void  +NFSPROC_NULL(void) = 0; +.DE +.KE +This procedure does no work.   It is made available  in  all RPC +services to allow server response testing and timing. +.KS +.NH 3 +\&Get File Attributes +.IX "NFS server procedures" NFSPROC_GETATTR() "" \fINFSPROC_GETATTR()\fP +.DS +attrstat  +NFSPROC_GETATTR (fhandle) = 1; +.DE +.KE +If the reply  status is  +.I NFS_OK , +then  the reply attributes contains +the attributes for the file given by the input fhandle. +.KS +.NH 3 +\&Set File Attributes +.IX "NFS server procedures" NFSPROC_SETATTR() "" \fINFSPROC_SETATTR()\fP +.DS +struct sattrargs { +	fhandle file; +	sattr attributes; +	}; + +attrstat +NFSPROC_SETATTR (sattrargs) = 2; +.DE +.KE +The  "attributes" argument  contains fields which are either  -1 or +are  the  new value for  the  attributes of  "file".   If the reply +status is  +.I NFS_OK , +then the  reply attributes have the attributes of +the file after the "SETATTR" operation has completed. +.LP +Note: The use of -1 to indicate an unused field in "attributes" is +changed in the next version of the protocol. +.KS +.NH 3 +\&Get Filesystem Root +.IX "NFS server procedures" NFSPROC_ROOT "" \fINFSPROC_ROOT\fP +.DS +void  +NFSPROC_ROOT(void) = 3; +.DE +.KE +Obsolete.  This procedure  is no longer used   because  finding the +root file handle of a filesystem requires moving  pathnames between +client  and server.  To  do  this right we would  have  to define a +network standard representation of pathnames.  Instead, the +function  of  looking up  the   root  file handle  is  done  by the +.I MNTPROC_MNT()  +procedure.    (See the +.I "Mount Protocol Definition" +later in this chapter for details). +.KS +.NH 3 +\&Look Up File Name +.IX "NFS server procedures" NFSPROC_LOOKUP() "" \fINFSPROC_LOOKUP()\fP +.DS +diropres +NFSPROC_LOOKUP(diropargs) = 4; +.DE +.KE +If  the reply "status"  is  +.I NFS_OK , +then the reply  "file" and reply +"attributes" are the file handle and attributes for the file "name" +in the directory given by "dir" in the argument. +.KS +.NH 3 +\&Read From Symbolic Link +.IX "NFS server procedures" NFSPROC_READLINK() "" \fINFSPROC_READLINK()\fP +.DS +union readlinkres switch (stat status) { +	case NFS_OK: +		path data; +	default: +		void; +}; + +readlinkres +NFSPROC_READLINK(fhandle) = 5; +.DE +.KE +If "status" has the value  +.I NFS_OK , +then the reply "data" is the data in  +the symbolic link given by the file referred to by the fhandle argument. +.LP +Note:  since   NFS always  parses pathnames    on the  client, the +pathname in  a symbolic  link may  mean something  different (or be +meaningless) on a different client or on the server if  a different +pathname syntax is used. +.KS +.NH 3 +\&Read From File +.IX "NFS server procedures" NFSPROC_READ "" \fINFSPROC_READ\fP +.DS +struct readargs { +	fhandle file; +	unsigned offset; +	unsigned count; +	unsigned totalcount; +}; + +union readres switch (stat status) { +	case NFS_OK: +		fattr attributes; +		opaque data<NFS_MAXDATA>; +	default: +		void; +}; + +readres +NFSPROC_READ(readargs) = 6; +.DE +.KE +Returns  up  to  "count" bytes of   "data" from  the file  given by +"file", starting at "offset" bytes from  the beginning of the file. +The first byte of the file is  at offset zero.  The file attributes +after the read takes place are returned in "attributes". +.LP +Note: The  argument "totalcount" is  unused, and is removed in the +next protocol revision. +.KS +.NH 3 +\&Write to Cache +.IX "NFS server procedures" NFSPROC_WRITECACHE() "" \fINFSPROC_WRITECACHE()\fP +.DS +void +NFSPROC_WRITECACHE(void) = 7; +.DE +.KE +To be used in the next protocol revision. +.KS +.NH 3 +\&Write to File +.IX "NFS server procedures" NFSPROC_WRITE() "" \fINFSPROC_WRITE()\fP +.DS +struct writeargs { +	fhandle file;           +	unsigned beginoffset;   +	unsigned offset;        +	unsigned totalcount;    +	opaque data<NFS_MAXDATA>; +}; + +attrstat	 +NFSPROC_WRITE(writeargs) = 8; +.DE +.KE +Writes   "data" beginning  "offset"  bytes  from the  beginning  of +"file".  The first byte  of  the file is at  offset  zero.  If  the +reply "status" is NFS_OK, then  the reply "attributes" contains the +attributes  of the file after the  write has  completed.  The write +operation is atomic.  Data from this  call to  +.I WRITE  +will not be mixed with data from another client's calls. +.LP +Note: The arguments "beginoffset" and "totalcount" are ignored and +are removed in the next protocol revision. +.KS +.NH 3 +\&Create File +.IX "NFS server procedures" NFSPROC_CREATE() "" \fINFSPROC_CREATE()\fP +.DS +struct createargs { +	diropargs where; +	sattr attributes; +}; + +diropres +NFSPROC_CREATE(createargs) = 9; +.DE +.KE +The file "name" is created  in the directory given  by "dir".   The +initial  attributes of the  new file  are given by "attributes".  A +reply "status"  of NFS_OK indicates that the  file was created, and +reply "file"   and   reply "attributes"  are    its file handle and +attributes.   Any  other reply  "status"  means that  the operation +failed and no file was created. +.LP +Note: This  routine should pass  an exclusive create flag, meaning +"create the file only if it is not already there". +.KS +.NH 3 +\&Remove File +.IX "NFS server procedures" NFSPROC_REMOVE() "" \fINFSPROC_REMOVE()\fP +.DS +stat +NFSPROC_REMOVE(diropargs) = 10; +.DE +.KE +The file "name" is  removed from the directory  given by "dir".   A +reply of NFS_OK means the directory entry was removed. +.LP +Note: possibly non-idempotent operation. +.KS +.NH 3 +\&Rename File +.IX "NFS server procedures" NFSPROC_RENAME() "" \fINFSPROC_RENAME()\fP +.DS +struct renameargs { +	diropargs from;	 +	diropargs to; +}; + +stat +NFSPROC_RENAME(renameargs) = 11; +.DE +.KE +The existing file "from.name" in  the directory given by "from.dir" +is renamed to "to.name" in the directory given by "to.dir".  If the +reply  is  +.I NFS_OK , +the file was  renamed.  The   +RENAME   +operation is +atomic on the server; it cannot be interrupted in the middle. +.LP +Note: possibly non-idempotent operation. +.KS +.NH 3 +\&Create Link to File +.IX "NFS server procedures" NFSPROC_LINK() "" \fINFSPROC_LINK()\fP +.DS +struct linkargs { +	fhandle from; +	diropargs to; +}; + +stat +NFSPROC_LINK(linkargs) = 12; +.DE +.KE +Creates the  file "to.name"  in the directory  given   by "to.dir", +which is a hard link to the existing file given  by "from".  If the +return value is  +.I NFS_OK , +a link was created.  Any other return value +indicates an error, and the link was not created. +.LP +A hard link should have the property that changes  to either of the +linked files are reflected in both files.  When a hard link is made +to a  file, the attributes  for  the file should  have  a value for +"nlink" that is one greater than the value before the link. +.LP +Note: possibly non-idempotent operation. +.KS +.NH 3 +\&Create Symbolic Link +.IX "NFS server procedures" NFSPROC_SYMLINK() "" \fINFSPROC_SYMLINK()\fP +.DS +struct symlinkargs { +	diropargs from; +	path to; +	sattr attributes; +}; + +stat +NFSPROC_SYMLINK(symlinkargs) = 13; +.DE +.KE +Creates the  file "from.name" with  ftype   +.I NFLNK  +in  the  directory +given by "from.dir".   The new file contains  the pathname "to" and +has initial attributes given by "attributes".  If  the return value +is  +.I NFS_OK , +a link was created.  Any other return value indicates an +error, and the link was not created. +.LP +A symbolic  link is  a pointer to another file.   The name given in +"to" is  not interpreted by  the server, only stored in  the  newly +created file.  When the client references a file that is a symbolic +link, the contents of the symbolic  link are normally transparently +reinterpreted  as a pathname  to substitute.   A  +.I READLINK  +operation returns the data to the client for interpretation. +.LP +Note:  On UNIX servers the attributes are never used, since +symbolic links always have mode 0777. +.KS +.NH 3 +\&Create Directory +.IX "NFS server procedures" NFSPROC_MKDIR() "" \fINFSPROC_MKDIR()\fP +.DS +diropres +NFSPROC_MKDIR (createargs) = 14; +.DE +.KE +The new directory "where.name" is created in the directory given by +"where.dir".  The initial attributes of the new directory are given +by "attributes".  A reply "status" of NFS_OK indicates that the new +directory was created, and reply "file" and  reply "attributes" are +its file  handle and attributes.  Any  other  reply "status"  means +that the operation failed and no directory was created. +.LP +Note: possibly non-idempotent operation. +.KS +.NH 3 +\&Remove Directory +.IX "NFS server procedures" NFSPROC_RMDIR() "" \fINFSPROC_RMDIR()\fP +.DS +stat +NFSPROC_RMDIR(diropargs) = 15; +.DE +.KE +The existing empty directory "name" in the directory given by "dir" +is removed.  If the reply is  +.I NFS_OK , +the directory was removed. +.LP +Note: possibly non-idempotent operation. +.KS +.NH 3 +\&Read From Directory +.IX "NFS server procedures" NFSPROC_READDIR() "" \fINFSPROC_READDIR()\fP +.DS +struct readdirargs { +	fhandle dir;             +	nfscookie cookie; +	unsigned count;          +}; + +struct entry { +	unsigned fileid; +	filename name; +	nfscookie cookie; +	entry *nextentry; +}; + +union readdirres switch (stat status) { +	case NFS_OK: +		struct { +			entry *entries; +			bool eof; +		} readdirok; +	default: +		void; +}; + +readdirres +NFSPROC_READDIR (readdirargs) = 16; +.DE +.KE +Returns a variable number of  directory entries,  with a total size +of up to "count" bytes, from the directory given  by "dir".  If the +returned  value of "status"  is  +.I NFS_OK , +then  it  is followed  by a +variable  number  of "entry"s.    Each "entry" contains  a "fileid" +which consists of a  unique number  to identify the  file within  a +filesystem,  the  "name" of the  file, and a "cookie" which   is an +opaque pointer to the next entry in  the  directory.  The cookie is +used  in the next   +.I READDIR  +call to get more  entries  starting at a +given point in  the directory.  The  special cookie zero (all  bits +zero) can be used to get the entries starting  at the  beginning of +the directory.  The "fileid" field should be the same number as the +"fileid" in the the  attributes of the  file.  (See the +.I "Basic Data Types" +section.)  +The "eof" flag has a value of +.I TRUE  +if there are no more entries in the directory. +.KS +.NH 3 +\&Get Filesystem Attributes +.IX "NFS server procedures" NFSPROC_STATFS() "" \fINFSPROC_STATFS()\fP +.DS +union statfsres (stat status) { +	case NFS_OK: +		struct { +			unsigned tsize;  +			unsigned bsize;  +			unsigned blocks; +			unsigned bfree;  +			unsigned bavail; +		} info; +	default: +		void; +}; + +statfsres +NFSPROC_STATFS(fhandle) = 17; +.DE +.KE +If the  reply "status"  is  +.I NFS_OK , +then the  reply "info" gives the +attributes for the filesystem that contains file referred to by the +input fhandle.  The attribute fields contain the following values: +.IP tsize:    +The optimum transfer size of the server in bytes.  This is +the number  of bytes the server  would like to have in the +data part of READ and WRITE requests. +.IP bsize:    +The block size in bytes of the filesystem. +.IP blocks:   +The total number of "bsize" blocks on the filesystem. +.IP bfree:    +The number of free "bsize" blocks on the filesystem. +.IP bavail:   +The number of  "bsize" blocks  available to non-privileged users. +.LP +Note: This call does not  work well if a  filesystem has  variable +size blocks. +.NH 1 +\&NFS Implementation Issues +.IX NFS implementation +.LP +The NFS protocol is designed to be operating system independent, but +since this version was designed in a UNIX environment, many +operations have semantics similar to the operations of the UNIX file +system.  This section discusses some of the implementation-specific +semantic issues. +.NH 2 +\&Server/Client Relationship +.IX NFS "server/client relationship" +.LP +The NFS protocol is designed to allow servers to be as simple and +general as possible.  Sometimes the simplicity of the server can be a +problem, if the client wants to implement complicated filesystem +semantics. +.LP +For example, some operating systems allow removal of open files.  A +process can open a file and, while it is open, remove it from the +directory.  The file can be read and written as long as the process +keeps it open, even though the file has no name in the filesystem. +It is impossible for a stateless server to implement these semantics. +The client can do some tricks such as renaming the file on remove, +and only removing it on close.  We believe that the server provides +enough functionality to implement most file system semantics on the +client. +.LP +Every NFS client can also potentially be a server, and remote and +local mounted filesystems can be freely intermixed.  This leads to +some interesting problems when a client travels down the directory +tree of a remote filesystem and reaches the mount point on the server +for another remote filesystem.  Allowing the server to follow the +second remote mount would require loop detection, server lookup, and +user revalidation.  Instead, we decided not to let clients cross a +server's mount point.  When a client does a LOOKUP on a directory on +which the server has mounted a filesystem, the client sees the +underlying directory instead of the mounted directory.  A client can +do remote mounts that match the server's mount points to maintain the +server's view. +.LP +.NH 2 +\&Pathname Interpretation +.IX NFS "pathname interpretation" +.LP +There are a few complications to the rule that pathnames are always +parsed on the client.  For example, symbolic links could have +different interpretations on different clients.  Another common +problem for non-UNIX implementations is the special interpretation of +the pathname ".."  to mean the parent of a given directory.  The next +revision of the protocol uses an explicit flag to indicate the parent +instead. +.NH 2 +\&Permission Issues +.IX NFS "permission issues" +.LP +The NFS protocol, strictly speaking, does not define the permission +checking used  by servers.  However,  it is  expected that a server +will do normal operating system permission checking using  +.I AUTH_UNIX  +style authentication as the basis of its protection mechanism.  The +server gets the client's effective "uid", effective "gid", and groups +on each call and uses them to check permission.  There are various +problems with this method that can been resolved in interesting ways. +.LP +Using "uid" and "gid" implies that the client and server share the +same "uid" list.  Every server and client pair must have the same +mapping from user to "uid" and from group to "gid".  Since every +client can also be a server, this tends to imply that the whole +network shares the same "uid/gid" space. +.I AUTH_DES  +(and the  next +revision of the NFS protocol) uses string names instead of numbers, +but there are still complex problems to be solved. +.LP +Another problem arises due to the usually stateful open operation. +Most operating systems check permission at open time, and then check +that the file is open on each read and write request.  With stateless +servers, the server has no idea that the file is open and must do +permission checking on each read and write call.  On a local +filesystem, a user can open a file and then change the permissions so +that no one is allowed to touch it, but will still be able to write +to the file because it is open.  On a remote filesystem, by contrast, +the write would fail.  To get around this problem, the server's +permission checking algorithm should allow the owner of a file to +access it regardless of the permission setting. +.LP +A similar problem has to do with paging in from a file over the +network.  The operating system usually checks for execute permission +before opening a file for demand paging, and then reads blocks from +the open file.  The file may not have read permission, but after it +is opened it doesn't matter.  An NFS server can not tell the +difference between a normal file read and a demand page-in read.  To +make this work, the server allows reading of files if the "uid" given +in the call has execute or read permission on the file. +.LP +In most operating systems, a particular user (on the user ID zero) +has access to all files no matter what permission and ownership they +have.  This "super-user" permission may not be allowed on the server, +since anyone who can become super-user on their workstation could +gain access to all remote files.  The UNIX server by default maps +user id 0 to -2 before doing its access checking.  This works except +for NFS root filesystems, where super-user access cannot be avoided. +.NH 2 +\&Setting RPC Parameters +.IX NFS "setting RPC parameters" +.LP +Various file system parameters and options should be set at mount +time.  The mount protocol is described in the appendix below.  For +example, "Soft" mounts as well as "Hard" mounts are usually both +provided.  Soft mounted file systems return errors when RPC +operations fail (after a given number of optional retransmissions), +while hard mounted file systems continue to retransmit forever. +Clients and servers may need to keep caches of recent operations to +help avoid problems with non-idempotent operations. +.NH 1 +\&Mount Protocol Definition +.IX "mount protocol" "" "" "" PAGE MAJOR +.sp 1 +.NH 2 +\&Introduction +.IX "mount protocol" introduction +.LP +The mount protocol is separate from, but related to, the NFS +protocol.  It provides operating system specific services to get the +NFS off the ground -- looking up server path names, validating user +identity, and checking access permissions.  Clients use the mount +protocol to get the first file handle, which allows them entry into a +remote filesystem. +.LP +The mount protocol is kept separate from the NFS protocol to make it +easy to plug in new access checking and validation methods without +changing the NFS server protocol. +.LP +Notice that the protocol definition implies stateful servers because +the server maintains a list of client's mount requests.  The mount +list information is not critical for the correct functioning of +either the client or the server.  It is intended for advisory use +only, for example, to warn possible clients when a server is going +down. +.LP +Version one of the mount protocol is used with version two of the NFS +protocol.  The only connecting point is the +.I fhandle  +structure, which is the same for both protocols. +.NH 2 +\&RPC Information +.IX "mount protocol"  "RPC information" +.IP \fIAuthentication\fP +The mount service uses  +.I AUTH_UNIX  +and  +.I AUTH_DES  +style authentication only. +.IP "\fITransport Protocols\fP" +The mount service is currently supported on UDP/IP only. +.IP "\fIPort Number\fP" +Consult the server's portmapper, described in the chapter +.I "Remote Procedure Calls: Protocol Specification", +to  find  the  port number on which the mount service is registered. +.NH 2 +\&Sizes of XDR Structures +.IX "mount protocol" "XDR structure sizes" +.LP +These  are  the sizes,   given  in  decimal   bytes, of various XDR +structures used in the protocol: +.DS +/* \fIThe maximum number of bytes in a pathname argument\fP */ +const MNTPATHLEN = 1024; + +/* \fIThe maximum number of bytes in a name argument\fP */ +const MNTNAMLEN = 255; + +/* \fIThe size in bytes of the opaque file handle\fP */ +const FHSIZE = 32; +.DE +.NH 2 +\&Basic Data Types +.IX "mount protocol" "basic data types" +.IX "mount data types" +.LP +This section presents the data  types used by  the  mount protocol. +In many cases they are similar to the types used in NFS. +.KS +.NH 3 +\&fhandle +.IX "mount data types" fhandle "" \fIfhandle\fP +.DS +typedef opaque fhandle[FHSIZE]; +.DE +.KE +The type  +.I fhandle  +is the file handle that the server passes to the +client.  All file operations are done  using file handles  to refer +to a  file  or directory.   The  file handle  can  contain whatever +information the server needs to distinguish an individual file. +.LP +This  is the  same as the "fhandle" XDR definition in version 2 of +the NFS protocol;  see  +.I "Basic Data Types" +in the definition of the NFS protocol, above. +.KS +.NH 3 +\&fhstatus +.IX "mount data types" fhstatus "" \fIfhstatus\fP +.DS +union fhstatus switch (unsigned status) { +	case 0: +		fhandle directory; +	default: +		void; +}; +.DE +.KE +The type  +.I fhstatus  +is a union.  If a "status" of zero is returned, +the  call completed   successfully, and  a  file handle   for   the +"directory"  follows.  A  non-zero  status indicates  some  sort of +error.  In this case the status is a UNIX error number. +.KS +.NH 3 +\&dirpath +.IX "mount data types" dirpath "" \fIdirpath\fP +.DS +typedef string dirpath<MNTPATHLEN>; +.DE +.KE +The type  +.I dirpath  +is a server pathname of a directory. +.KS +.NH 3 +\&name +.IX "mount data types" name "" \fIname\fP +.DS +typedef string name<MNTNAMLEN>; +.DE +.KE +The type  +.I name  +is an arbitrary string used for various names. +.NH 2 +\&Server Procedures +.IX "mount server procedures" +.LP +The following sections define the RPC procedures  supplied by a +mount server. +.ie t .DS +.el .DS L +.ft I +/* +* Protocol description for the mount program +*/ +.ft CW + +program MOUNTPROG { +.ft I +/* +* Version 1 of the mount protocol used with +* version 2 of the NFS protocol. +*/ +.ft CW +	version MOUNTVERS { +		void        MOUNTPROC_NULL(void)    = 0; +		fhstatus    MOUNTPROC_MNT(dirpath)  = 1; +		mountlist   MOUNTPROC_DUMP(void)    = 2; +		void        MOUNTPROC_UMNT(dirpath) = 3; +		void        MOUNTPROC_UMNTALL(void) = 4; +		exportlist  MOUNTPROC_EXPORT(void)  = 5; +	} = 1; +} = 100005; +.DE +.KS +.NH 3 +\&Do Nothing +.IX "mount server procedures" MNTPROC_NULL() "" \fIMNTPROC_NULL()\fP +.DS +void  +MNTPROC_NULL(void) = 0; +.DE +.KE +This  procedure does no work.  It   is  made  available in all  RPC +services to allow server response testing and timing. +.KS +.NH 3 +\&Add Mount Entry +.IX "mount server procedures" MNTPROC_MNT() "" \fIMNTPROC_MNT()\fP +.DS +fhstatus +MNTPROC_MNT(dirpath) = 1; +.DE +.KE +If the reply "status" is 0, then the reply "directory" contains the +file handle for the directory "dirname".  This file handle may be +used in the NFS protocol.  This procedure also adds a new entry to +the mount list for this client mounting "dirname". +.KS +.NH 3 +\&Return Mount Entries +.IX "mount server procedures" MNTPROC_DUMP() "" \fIMNTPROC_DUMP()\fP +.DS +struct *mountlist { +	name      hostname; +	dirpath   directory; +	mountlist nextentry; +}; + +mountlist +MNTPROC_DUMP(void) = 2; +.DE +.KE +Returns  the list of  remote mounted filesystems.   The "mountlist" +contains one entry for each "hostname" and "directory" pair. +.KS +.NH 3 +\&Remove Mount Entry +.IX "mount server procedures" MNTPROC_UMNT() "" \fIMNTPROC_UMNT()\fP +.DS +void +MNTPROC_UMNT(dirpath) = 3; +.DE +.KE +Removes the mount list entry for the input "dirpath". +.KS +.NH 3 +\&Remove All Mount Entries +.IX "mount server procedures" MNTPROC_UMNTALL() "" \fIMNTPROC_UMNTALL()\fP +.DS +void +MNTPROC_UMNTALL(void) = 4; +.DE +.KE +Removes all of the mount list entries for this client. +.KS +.NH 3 +\&Return Export List +.IX "mount server procedures" MNTPROC_EXPORT() "" \fIMNTPROC_EXPORT()\fP +.DS +struct *groups { +	name grname; +	groups grnext; +}; + +struct *exportlist { +	dirpath filesys; +	groups groups; +	exportlist next; +}; + +exportlist +MNTPROC_EXPORT(void) = 5; +.DE +.KE +Returns a variable number of export list entries.  Each entry +contains a filesystem name and a list of groups that are allowed to +import it.  The filesystem name is in "filesys", and the group name +is in the list "groups". +.LP +Note:  The exportlist should contain +more information about the status of the filesystem, such as a +read-only flag. diff --git a/lib/librpc/doc/rpc.prog.ms b/lib/librpc/doc/rpc.prog.ms new file mode 100644 index 000000000000..3b02447fe84a --- /dev/null +++ b/lib/librpc/doc/rpc.prog.ms @@ -0,0 +1,2684 @@ +.\" +.\" Must use -- tbl and pic -- with this one +.\" +.\" @(#)rpc.prog.ms	2.3 88/08/11 4.0 RPCSRC +.de BT +.if \\n%=1 .tl ''- % -'' +.. +.IX "Network Programming" "" "" "" PAGE MAJOR +.nr OF 0 +.ND +.\" prevent excess underlining in nroff +.if n .fp 2 R +.OH 'Remote Procedure Call Programming Guide''Page %' +.EH 'Page %''Remote Procedure Call Programming Guide' +.SH +\&Remote Procedure Call Programming Guide +.nr OF 1 +.IX "RPC Programming Guide" +.LP +This document assumes a working knowledge of network theory.  It is +intended for programmers who wish to write network applications using +remote procedure calls (explained below), and who want to understand +the RPC mechanisms usually hidden by the +.I rpcgen(1)  +protocol compiler. +.I rpcgen  +is described in detail in the previous chapter, the +.I "\fBrpcgen\fP \fIProgramming Guide\fP". +.SH +Note: +.I +.IX rpcgen "" \fIrpcgen\fP +Before attempting to write a network application, or to convert an +existing non-network application to run over the network, you may want to +understand the material in this chapter.  However, for most applications, +you can circumvent the need to cope with the details presented here by using +.I rpcgen . +The +.I "Generating XDR Routines" +section of that chapter contains the complete source for a working RPC +service\(ema remote directory listing service which uses +.I rpcgen  +to generate XDR routines as well as client and server stubs. +.LP +.LP +What are remote procedure calls?  Simply put, they are the high-level +communications paradigm used in the operating system. +RPC presumes the existence of +low-level networking mechanisms (such as TCP/IP and UDP/IP), and upon them +it implements a logical client to server communications system designed +specifically for the support of network applications.  With RPC, the client +makes a procedure call to send a data packet to the server.  When the +packet arrives, the server calls a dispatch routine, performs whatever +service is requested, sends back the reply, and the procedure call returns +to the client. +.NH 0 +\&Layers of RPC +.IX "layers of RPC" +.IX "RPC" "layers" +.LP +The RPC interface can be seen as being divided into three layers.\** +.FS +For a complete specification of the routines in the remote procedure +call Library, see the +.I rpc(3N)  +manual page. +.FE +.LP +.I "The Highest Layer:" +.IX RPC "The Highest Layer" +The highest layer is totally transparent to the operating system,  +machine and network upon which is is run.  It's probably best to  +think of this level as a way of +.I using +RPC, rather than as +a \fIpart of\fP RPC proper.  Programmers who write RPC routines  +should (almost) always make this layer available to others by way  +of a simple C front end that entirely hides the networking. +.LP  +To illustrate, at this level a program can simply make a call to +.I rnusers (), +a C routine which returns the number of users on a remote machine. +The user is not explicitly aware of using RPC \(em they simply  +call a procedure, just as they would call +.I malloc() . +.LP +.I "The Middle Layer:" +.IX RPC "The Middle Layer" +The middle layer is really \*QRPC proper.\*U  Here, the user doesn't +need to consider details about sockets, the UNIX system, or other low-level  +implementation mechanisms.  They simply make remote procedure calls +to routines on other machines.  The selling point here is simplicity.   +It's this layer that allows RPC to pass the \*Qhello world\*U test \(em +simple things should be simple.  The middle-layer routines are used  +for most applications. +.LP +RPC calls are made with the system routines +.I registerrpc() +.I callrpc() +and +.I svc_run (). +The first two of these are the most fundamental: +.I registerrpc()  +obtains a unique system-wide procedure-identification number, and +.I callrpc()  +actually executes a remote procedure call.  At the middle level, a  +call to  +.I rnusers() +is implemented by way of these two routines. +.LP +The middle layer is unfortunately rarely used in serious programming  +due to its inflexibility (simplicity).  It does not allow timeout  +specifications or the choice of transport.  It allows no UNIX +process control or flexibility in case of errors.  It doesn't support +multiple kinds of call authentication.  The programmer rarely needs  +all these kinds of control, but one or two of them is often necessary. +.LP +.I "The Lowest Layer:" +.IX RPC "The Lowest Layer" +The lowest layer does allow these details to be controlled by the  +programmer, and for that reason it is often necessary.  Programs  +written at this level are also most efficient, but this is rarely a +real issue \(em since RPC clients and servers rarely generate  +heavy network loads. +.LP +Although this document only discusses the interface to C, +remote procedure calls can be made from any language. +Even though this document discusses RPC +when it is used to communicate +between processes on different machines, +it works just as well for communication +between different processes on the same machine. +.br +.KS +.NH 2 +\&The RPC Paradigm +.IX RPC paradigm +.LP +Here is a diagram of the RPC paradigm: +.LP +\fBFigure 1-1\fI Network Communication with the Remote Reocedure Call\fR +.LP +.PS +L1: arrow down 1i "client " rjust "program " rjust +L2: line right 1.5i "\fIcallrpc\fP" "function" +move up 1.5i; line dotted down 6i; move up 4.5i +arrow right 1i +L3: arrow down 1i "invoke " rjust "service " rjust +L4: arrow right 1.5i "call" "service" +L5: arrow down 1i " service" ljust " executes" ljust +L6: arrow left 1.5i "\fIreturn\fP" "answer" +L7: arrow down 1i "request " rjust "completed " rjust +L8: line left 1i +arrow left 1.5i "\fIreturn\fP" "reply" +L9: arrow down 1i "program " rjust "continues " rjust +line dashed down from L2 to L9 +line dashed down from L4 to L7 +line dashed up 1i from L3 "service " rjust "daemon " rjust +arrow dashed down 1i from L8 +move right 1i from L3 +box invis "Machine B" +move left 1.2i from L2; move down +box invis "Machine A" +.PE +.KE +.KS +.NH 1 +\&Higher Layers of RPC +.NH 2 +\&Highest Layer +.IX "highest layer of RPC" +.IX RPC "highest layer" +.LP +Imagine you're writing a program that needs to know +how many users are logged into a remote machine. +You can do this by calling the RPC library routine +.I rnusers() +as illustrated below: +.ie t .DS +.el .DS L +.ft CW +#include <stdio.h> + +main(argc, argv) +	int argc; +	char **argv; +{ +	int num; + +	if (argc != 2) { +		fprintf(stderr, "usage: rnusers hostname\en"); +		exit(1); +	} +	if ((num = rnusers(argv[1])) < 0) { +		fprintf(stderr, "error: rnusers\en"); +		exit(-1); +	} +	printf("%d users on %s\en", num, argv[1]); +	exit(0); +} +.DE +.KE +RPC library routines such as +.I rnusers()  +are in the RPC services library +.I librpcsvc.a +Thus, the program above should be compiled with +.DS +.ft CW +% cc \fIprogram.c -lrpcsvc\fP +.DE +.I rnusers (), +like the other RPC library routines, is documented in section 3R  +of the +.I "System Interface Manual for the Sun Workstation" , +the same section which documents the standard Sun RPC services.   +.IX "RPC Services" +See the  +.I intro(3R)  +manual page for an explanation of the documentation strategy  +for these services and their RPC protocols. +.LP +Here are some of the RPC service library routines available to the  +C programmer: +.LP +\fBTable 3-3\fI RPC Service Library Routines\RP +.TS +box tab (&) ; +cfI cfI +lfL l . +Routine&Description +_ +.sp.5 +rnusers&Return number of users on remote machine +rusers&Return information about users on remote machine +havedisk&Determine if remote machine has disk +rstats&Get performance data from remote kernel +rwall&Write to specified remote machines +yppasswd&Update user password in Yellow Pages +.TE +.LP +Other RPC services \(em for example +.I ether() +.I mount +.I rquota() +and +.I spray +\(em are not available to the C programmer as library routines. +They do, however, +have RPC program numbers so they can be invoked with +.I callrpc() +which will be discussed in the next section.  Most of them also  +have compilable  +.I rpcgen(1)  +protocol description files.  (The +.I rpcgen +protocol compiler radically simplifies the process of developing +network applications.   +See the \fBrpcgen\fI Programming Guide\fR +for detailed information about  +.I rpcgen  +and  +.I rpcgen  +protocol description files). +.KS +.NH 2 +\&Intermediate Layer +.IX "intermediate layer of RPC" +.IX "RPC" "intermediate layer" +.LP +The simplest interface, which explicitly makes RPC calls, uses the  +functions +.I callrpc() +and +.I registerrpc() +Using this method, the number of remote users can be gotten as follows: +.ie t .DS +.el .DS L +#include <stdio.h> +#include <rpc/rpc.h> +#include <utmp.h> +#include <rpcsvc/rusers.h> + +main(argc, argv) +	int argc; +	char **argv; +{ +	unsigned long nusers; +	int stat; + +	if (argc != 2) { +		fprintf(stderr, "usage: nusers hostname\en"); +		exit(-1); +	} +	if (stat = callrpc(argv[1], +	  RUSERSPROG, RUSERSVERS, RUSERSPROC_NUM, +	  xdr_void, 0, xdr_u_long, &nusers) != 0) { +		clnt_perrno(stat); +		exit(1); +	} +	printf("%d users on %s\en", nusers, argv[1]); +	exit(0); +} +.DE +.KE +Each RPC procedure is uniquely defined by a program number,  +version number, and procedure number.  The program number  +specifies a group of related remote procedures, each of  +which has a different procedure number.  Each program also  +has a version number, so when a minor change is made to a  +remote service (adding a new procedure, for example), a new  +program number doesn't have to be assigned.  When you want  +to call a procedure to find the number of remote users, you  +look up the appropriate program, version and procedure numbers +in a manual, just as you look up the name of a memory allocator  +when you want to allocate memory. +.LP +The simplest way of making remote procedure calls is with the the RPC  +library routine +.I callrpc() +It has eight parameters.  The first is the name of the remote server  +machine.  The next three parameters are the program, version, and procedure  +numbers\(emtogether they identify the procedure to be called. +The fifth and sixth parameters are an XDR filter and an argument to +be encoded and passed to the remote procedure.   +The final two parameters are a filter for decoding the results  +returned by the remote procedure and a pointer to the place where  +the procedure's results are to be stored.  Multiple arguments and +results are handled by embedding them in structures.  If  +.I callrpc()  +completes successfully, it returns zero; else it returns a nonzero  +value.  The return codes (of type +.IX "enum clnt_stat (in RPC programming)" "" "\fIenum clnt_stat\fP (in RPC programming)" +cast into an integer) are found in  +.I <rpc/clnt.h> . +.LP +Since data types may be represented differently on different machines, +.I callrpc()  +needs both the type of the RPC argument, as well as +a pointer to the argument itself (and similarly for the result).  For +.I RUSERSPROC_NUM , +the return value is an +.I "unsigned long" +so +.I callrpc()  +has +.I xdr_u_long()  +as its first return parameter, which says +that the result is of type +.I "unsigned long" +and +.I &nusers  +as its second return parameter, +which is a pointer to where the long result will be placed.  Since +.I RUSERSPROC_NUM  +takes no argument, the argument parameter of +.I callrpc()  +is +.I xdr_void (). +.LP +After trying several times to deliver a message, if +.I callrpc()  +gets no answer, it returns with an error code. +The delivery mechanism is UDP, +which stands for User Datagram Protocol. +Methods for adjusting the number of retries +or for using a different protocol require you to use the lower +layer of the RPC library, discussed later in this document. +The remote server procedure +corresponding to the above might look like this: +.ie t .DS +.el .DS L +.ft CW +.ft CW +char * +nuser(indata) +	char *indata; +{ +	unsigned long nusers; + +.ft I +	/* +	 * Code here to compute the number of users +	 * and place result in variable \fInusers\fP. +	 */ +.ft CW +	return((char *)&nusers); +} +.DE +.LP +It takes one argument, which is a pointer to the input +of the remote procedure call (ignored in our example), +and it returns a pointer to the result. +In the current version of C, +character pointers are the generic pointers, +so both the input argument and the return value are cast to +.I "char *" . +.LP +Normally, a server registers all of the RPC calls it plans +to handle, and then goes into an infinite loop waiting to service requests. +In this example, there is only a single procedure +to register, so the main body of the server would look like this: +.ie t .DS +.el .DS L +.ft CW +#include <stdio.h> +#include <rpc/rpc.h> +#include <utmp.h> +#include <rpcsvc/rusers.h> + +char *nuser(); + +main() +{ +	registerrpc(RUSERSPROG, RUSERSVERS, RUSERSPROC_NUM, +		nuser, xdr_void, xdr_u_long); +	svc_run();		/* \fINever returns\fP */ +	fprintf(stderr, "Error: svc_run returned!\en"); +	exit(1); +} +.DE +.LP +The +.I registerrpc() +routine registers a C procedure as corresponding to a +given RPC procedure number.  The first three parameters, +.I RUSERPROG , +.I RUSERSVERS , +and +.I RUSERSPROC_NUM  +are the program, version, and procedure numbers +of the remote procedure to be registered; +.I nuser()  +is the name of the local procedure that implements the remote +procedure; and +.I xdr_void()  +and +.I xdr_u_long()  +are the XDR filters for the remote procedure's arguments and +results, respectively.  (Multiple arguments or multiple results +are passed as structures). +.LP +Only the UDP transport mechanism can use +.I registerrpc() +thus, it is always safe in conjunction with calls generated by +.I callrpc() . +.SH +.IX "UDP 8K warning" +Warning: the UDP transport mechanism can only deal with +arguments and results less than 8K bytes in length. +.LP +.LP +After registering the local procedure, the server program's +main procedure calls +.I svc_run (), +the RPC library's remote procedure dispatcher.  It is this  +function that calls the remote procedures in response to RPC +call messages.  Note that the dispatcher takes care of decoding +remote procedure arguments and encoding results, using the XDR +filters specified when the remote procedure was registered. +.NH 2 +\&Assigning Program Numbers +.IX "program number assignment" +.IX "assigning program numbers" +.LP +Program numbers are assigned in groups of  +.I 0x20000000  +according to the following chart: +.DS +.ft CW +       0x0 - 0x1fffffff	\fRDefined by Sun\fP +0x20000000 - 0x3fffffff	\fRDefined by user\fP +0x40000000 - 0x5fffffff	\fRTransient\fP +0x60000000 - 0x7fffffff	\fRReserved\fP +0x80000000 - 0x9fffffff	\fRReserved\fP +0xa0000000 - 0xbfffffff	\fRReserved\fP +0xc0000000 - 0xdfffffff	\fRReserved\fP +0xe0000000 - 0xffffffff	\fRReserved\fP +.ft R +.DE +Sun Microsystems administers the first group of numbers, which +should be identical for all Sun customers.  If a customer +develops an application that might be of general interest, that +application should be given an assigned number in the first +range.  The second group of numbers is reserved for specific +customer applications.  This range is intended primarily for +debugging new programs.  The third group is reserved for +applications that generate program numbers dynamically.  The +final groups are reserved for future use, and should not be +used. +.LP +To register a protocol specification, send a request by network  +mail to +.I rpc@sun +or write to: +.DS +RPC Administrator +Sun Microsystems +2550 Garcia Ave. +Mountain View, CA 94043 +.DE +Please include a compilable  +.I rpcgen  +\*Q.x\*U file describing your protocol. +You will be given a unique program number in return. +.IX RPC administration +.IX administration "of RPC" +.LP +The RPC program numbers and protocol specifications  +of standard Sun RPC services can be +found in the include files in  +.I "/usr/include/rpcsvc" . +These services, however, constitute only a small subset  +of those which have been registered.  The complete list of  +registered programs, as of the time when this manual was  +printed, is: +.LP +\fBTable 3-2\fI RPC Registered Programs\fR +.TS H +box tab (&) ; +lfBI lfBI lfBI +lfL lfL lfI . +RPC Number&Program&Description +_ +.TH +.sp.5 +100000&PMAPPROG&portmapper +100001&RSTATPROG&remote stats             +100002&RUSERSPROG&remote users             +100003&NFSPROG&nfs                      +100004&YPPROG&Yellow Pages             +100005&MOUNTPROG&mount demon              +100006&DBXPROG&remote dbx               +100007&YPBINDPROG&yp binder                +100008&WALLPROG&shutdown msg             +100009&YPPASSWDPROG&yppasswd server          +100010ÐERSTATPROGðer stats              +100011&RQUOTAPROG&disk quotas              +100012&SPRAYPROG&spray packets            +100013&IBM3270PROG&3270 mapper              +100014&IBMRJEPROG&RJE mapper               +100015&SELNSVCPROG&selection service        +100016&RDATABASEPROG&remote database access   +100017&REXECPROG&remote execution         +100018&ALICEPROG&Alice Office Automation  +100019&SCHEDPROG&scheduling service       +100020&LOCKPROG&local lock manager       +100021&NETLOCKPROG&network lock manager     +100022&X25PROG&x.25 inr protocol        +100023&STATMON1PROG&status monitor 1         +100024&STATMON2PROG&status monitor 2         +100025&SELNLIBPROG&selection library        +100026&BOOTPARAMPROG&boot parameters service  +100027&MAZEPROG&mazewars game            +100028&YPUPDATEPROG&yp update                +100029&KEYSERVEPROG&key server               +100030&SECURECMDPROG&secure login             +100031&NETFWDIPROG&nfs net forwarder init	 +100032&NETFWDTPROG&nfs net forwarder trans	 +100033&SUNLINKMAP_PROG&sunlink MAP		 +100034&NETMONPROG&network monitor		 +100035&DBASEPROG&lightweight database	 +100036&PWDAUTHPROG&password authorization	 +100037&TFSPROG&translucent file svc	 +100038&NSEPROG&nse server		 +100039&NSE_ACTIVATE_PROG&nse activate daemon	 +.sp .2i +150001&PCNFSDPROG&pc passwd authorization  +.sp .2i +200000&PYRAMIDLOCKINGPROG&Pyramid-locking          +200001&PYRAMIDSYS5&Pyramid-sys5             +200002&CADDS_IMAGE&CV cadds_image		 +.sp .2i +300001&ADT_RFLOCKPROG&ADT file locking	 +.TE +.NH 2 +\&Passing Arbitrary Data Types +.IX "arbitrary data types" +.LP +In the previous example, the RPC call passes a single +.I "unsigned long" +RPC can handle arbitrary data structures, regardless of +different machines' byte orders or structure layout conventions, +by always converting them to a network standard called +.I "External Data Representation" +(XDR) before +sending them over the wire. +The process of converting from a particular machine representation +to XDR format is called +.I serializing , +and the reverse process is called +.I deserializing . +The type field parameters of +.I callrpc()  +and +.I registerrpc()  +can be a built-in procedure like +.I xdr_u_long()  +in the previous example, or a user supplied one. +XDR has these built-in type routines: +.IX RPC "built-in routines" +.DS +.ft CW +xdr_int()      xdr_u_int()      xdr_enum() +xdr_long()     xdr_u_long()     xdr_bool() +xdr_short()    xdr_u_short()    xdr_wrapstring() +xdr_char()     xdr_u_char() +.DE +Note that the routine +.I xdr_string()  +exists, but cannot be used with  +.I callrpc()  +and +.I registerrpc (), +which only pass two parameters to their XDR routines. +.I xdr_wrapstring()  +has only two parameters, and is thus OK.  It calls  +.I xdr_string (). +.LP +As an example of a user-defined type routine, +if you wanted to send the structure +.DS +.ft CW +struct simple { +	int a; +	short b; +} simple; +.DE +then you would call +.I callrpc()  +as +.DS +.ft CW +callrpc(hostname, PROGNUM, VERSNUM, PROCNUM, +        xdr_simple, &simple ...); +.DE +where +.I xdr_simple()  +is written as: +.ie t .DS +.el .DS L +.ft CW +#include <rpc/rpc.h> + +xdr_simple(xdrsp, simplep) +	XDR *xdrsp; +	struct simple *simplep; +{ +	if (!xdr_int(xdrsp, &simplep->a)) +		return (0); +	if (!xdr_short(xdrsp, &simplep->b)) +		return (0); +	return (1); +} +.DE +.LP +An XDR routine returns nonzero (true in the sense of C) if it  +completes successfully, and zero otherwise. +A complete description of XDR is in the +.I "XDR Protocol Specification"  +section of this manual, only few implementation examples are  +given here. +.LP +In addition to the built-in primitives, +there are also the prefabricated building blocks: +.DS +.ft CW +xdr_array()       xdr_bytes()     xdr_reference() +xdr_vector()      xdr_union()     xdr_pointer() +xdr_string()      xdr_opaque() +.DE +To send a variable array of integers, +you might package them up as a structure like this +.DS +.ft CW +struct varintarr { +	int *data; +	int arrlnth; +} arr; +.DE +and make an RPC call such as +.DS +.ft CW +callrpc(hostname, PROGNUM, VERSNUM, PROCNUM, +        xdr_varintarr, &arr...); +.DE +with +.I xdr_varintarr()  +defined as: +.ie t .DS +.el .DS L +.ft CW +xdr_varintarr(xdrsp, arrp) +	XDR *xdrsp; +	struct varintarr *arrp; +{ +	return (xdr_array(xdrsp, &arrp->data, &arrp->arrlnth,  +		MAXLEN, sizeof(int), xdr_int)); +} +.DE +This routine takes as parameters the XDR handle, +a pointer to the array, a pointer to the size of the array, +the maximum allowable array size, +the size of each array element, +and an XDR routine for handling each array element. +.KS +.LP +If the size of the array is known in advance, one can use +.I xdr_vector (), +which serializes fixed-length arrays. +.ie t .DS +.el .DS L +.ft CW +int intarr[SIZE]; + +xdr_intarr(xdrsp, intarr) +	XDR *xdrsp; +	int intarr[]; +{ +	int i; + +	return (xdr_vector(xdrsp, intarr, SIZE, sizeof(int), +		xdr_int)); +} +.DE +.KE +.LP +XDR always converts quantities to 4-byte multiples when serializing. +Thus, if either of the examples above involved characters +instead of integers, each character would occupy 32 bits. +That is the reason for the XDR routine +.I xdr_bytes() +which is like +.I xdr_array() +except that it packs characters; +.I xdr_bytes()  +has four parameters, similar to the first four parameters of +.I xdr_array (). +For null-terminated strings, there is also the +.I xdr_string() +routine, which is the same as +.I xdr_bytes()  +without the length parameter. +On serializing it gets the string length from +.I strlen (), +and on deserializing it creates a null-terminated string. +.LP +Here is a final example that calls the previously written +.I xdr_simple()  +as well as the built-in functions +.I xdr_string()  +and +.I xdr_reference (), +which chases pointers: +.ie t .DS +.el .DS L +.ft CW +struct finalexample { +	char *string; +	struct simple *simplep; +} finalexample; + +xdr_finalexample(xdrsp, finalp) +	XDR *xdrsp; +	struct finalexample *finalp; +{ + +	if (!xdr_string(xdrsp, &finalp->string, MAXSTRLEN)) +		return (0); +	if (!xdr_reference(xdrsp, &finalp->simplep, +	  sizeof(struct simple), xdr_simple); +		return (0); +	return (1); +} +.DE +Note that we could as easily call +.I xdr_simple()  +here instead of +.I xdr_reference (). +.NH 1 +\&Lowest Layer of RPC +.IX "lowest layer of RPC" +.IX "RPC" "lowest layer" +.LP +In the examples given so far, +RPC takes care of many details automatically for you. +In this section, we'll show you how you can change the defaults +by using lower layers of the RPC library. +It is assumed that you are familiar with sockets +and the system calls for dealing with them. +.LP +There are several occasions when you may need to use lower layers of  +RPC.  First, you may need to use TCP, since the higher layer uses UDP,  +which restricts RPC calls to 8K bytes of data.  Using TCP permits calls  +to send long streams of data.   +For an example, see the +.I TCP +section below.  Second, you may want to allocate and free memory +while serializing or deserializing with XDR routines.   +There is no call at the higher level to let  +you free memory explicitly.   +For more explanation, see the +.I "Memory Allocation with XDR" +section below.   +Third, you may need to perform authentication  +on either the client or server side, by supplying  +credentials or verifying them. +See the explanation in the  +.I Authentication +section below. +.NH 2 +\&More on the Server Side +.IX RPC "server side" +.LP +The server for the +.I nusers()  +program shown below does the same thing as the one using +.I registerrpc()  +above, but is written using a lower layer of the RPC package: +.ie t .DS +.el .DS L +.ft CW +#include <stdio.h> +#include <rpc/rpc.h> +#include <utmp.h> +#include <rpcsvc/rusers.h> + +main() +{ +	SVCXPRT *transp; +	int nuser(); + +	transp = svcudp_create(RPC_ANYSOCK); +	if (transp == NULL){ +		fprintf(stderr, "can't create an RPC server\en"); +		exit(1); +	} +	pmap_unset(RUSERSPROG, RUSERSVERS); +	if (!svc_register(transp, RUSERSPROG, RUSERSVERS, +			  nuser, IPPROTO_UDP)) { +		fprintf(stderr, "can't register RUSER service\en"); +		exit(1); +	} +	svc_run();  /* \fINever returns\fP */ +	fprintf(stderr, "should never reach this point\en"); +} + +nuser(rqstp, transp) +	struct svc_req *rqstp; +	SVCXPRT *transp; +{ +	unsigned long nusers; + +	switch (rqstp->rq_proc) { +	case NULLPROC: +		if (!svc_sendreply(transp, xdr_void, 0)) +			fprintf(stderr, "can't reply to RPC call\en"); +		return; +	case RUSERSPROC_NUM: +.ft I +		/* +		 * Code here to compute the number of users +		 * and assign it to the variable \fInusers\fP +		 */ +.ft CW +		if (!svc_sendreply(transp, xdr_u_long, &nusers))  +			fprintf(stderr, "can't reply to RPC call\en"); +		return; +	default: +		svcerr_noproc(transp); +		return; +	} +} +.DE +.LP +First, the server gets a transport handle, which is used +for receiving and replying to RPC messages. +.I registerrpc()  +uses +.I svcudp_create() +to get a UDP handle. +If you require a more reliable protocol, call +.I svctcp_create() +instead. +If the argument to +.I svcudp_create()  +is +.I RPC_ANYSOCK +the RPC library creates a socket +on which to receive and reply to RPC calls.  Otherwise, +.I svcudp_create()  +expects its argument to be a valid socket number. +If you specify your own socket, it can be bound or unbound. +If it is bound to a port by the user, the port numbers of +.I svcudp_create()  +and +.I clnttcp_create() +(the low-level client routine) must match. +.LP +If the user specifies the +.I RPC_ANYSOCK  +argument, the RPC library routines will open sockets. +Otherwise they will expect the user to do so.  The routines +.I svcudp_create()  +and  +.I clntudp_create() +will cause the RPC library routines to +.I bind()  +their socket if it is not bound already. +.LP +A service may choose to register its port number with the +local portmapper service.  This is done is done by specifying +a non-zero protocol number in +.I svc_register (). +Incidently, a client can discover the server's port number by  +consulting the portmapper on their server's machine.  This can  +be done automatically by specifying a zero port number in  +.I clntudp_create()  +or +.I clnttcp_create (). +.LP +After creating an +.I SVCXPRT , +the next step is to call +.I pmap_unset() +so that if the +.I nusers()  +server crashed earlier, +any previous trace of it is erased before restarting. +More precisely, +.I pmap_unset()  +erases the entry for +.I RUSERSPROG +from the port mapper's tables. +.LP +Finally, we associate the program number for +.I nusers()  +with the procedure +.I nuser (). +The final argument to +.I svc_register()  +is normally the protocol being used, +which, in this case, is +.I IPPROTO_UDP +Notice that unlike +.I registerrpc (), +there are no XDR routines involved +in the registration process. +Also, registration is done on the program, +rather than procedure, level. +.LP +The user routine +.I nuser()  +must call and dispatch the appropriate XDR routines +based on the procedure number. +Note that +two things are handled by +.I nuser()  +that +.I registerrpc()  +handles automatically. +The first is that procedure +.I NULLPROC +(currently zero) returns with no results. +This can be used as a simple test +for detecting if a remote program is running. +Second, there is a check for invalid procedure numbers. +If one is detected, +.I svcerr_noproc() +is called to handle the error. +.KS +.LP +The user service routine serializes the results and returns +them to the RPC caller via +.I svc_sendreply() +Its first parameter is the +.I SVCXPRT +handle, the second is the XDR routine, +and the third is a pointer to the data to be returned. +Not illustrated above is how a server +handles an RPC program that receives data. +As an example, we can add a procedure +.I RUSERSPROC_BOOL +which has an argument +.I nusers (), +and returns +.I TRUE  +or +.I FALSE  +depending on whether there are nusers logged on. +It would look like this: +.ie t .DS +.el .DS L +.ft CW +case RUSERSPROC_BOOL: { +	int bool; +	unsigned nuserquery; + +	if (!svc_getargs(transp, xdr_u_int, &nuserquery) { +		svcerr_decode(transp); +		return; +	} +.ft I +	/* +	 * Code to set \fInusers\fP = number of users +	 */ +.ft CW +	if (nuserquery == nusers) +		bool = TRUE; +	else +		bool = FALSE; +	if (!svc_sendreply(transp, xdr_bool, &bool)) { +		 fprintf(stderr, "can't reply to RPC call\en"); +		 return (1); +	} +	return; +} +.DE +.KE +.LP +The relevant routine is +.I svc_getargs() +which takes an +.I SVCXPRT +handle, the XDR routine, +and a pointer to where the input is to be placed as arguments. +.NH 2 +\&Memory Allocation with XDR +.IX "memory allocation with XDR" +.IX XDR "memory allocation" +.LP +XDR routines not only do input and output, +they also do memory allocation. +This is why the second parameter of +.I xdr_array() +is a pointer to an array, rather than the array itself. +If it is +.I NULL , +then +.I xdr_array() +allocates space for the array and returns a pointer to it, +putting the size of the array in the third argument. +As an example, consider the following XDR routine +.I xdr_chararr1() +which deals with a fixed array of bytes with length +.I SIZE . +.ie t .DS +.el .DS L +.ft CW +xdr_chararr1(xdrsp, chararr) +	XDR *xdrsp; +	char chararr[]; +{ +	char *p; +	int len; + +	p = chararr; +	len = SIZE; +	return (xdr_bytes(xdrsp, &p, &len, SIZE)); +} +.DE +If space has already been allocated in +.I chararr , +it can be called from a server like this: +.ie t .DS +.el .DS L +.ft CW +char chararr[SIZE]; + +svc_getargs(transp, xdr_chararr1, chararr); +.DE +If you want XDR to do the allocation, +you would have to rewrite this routine in the following way: +.ie t .DS +.el .DS L +.ft CW +xdr_chararr2(xdrsp, chararrp) +	XDR *xdrsp; +	char **chararrp; +{ +	int len; + +	len = SIZE; +	return (xdr_bytes(xdrsp, charrarrp, &len, SIZE)); +} +.DE +Then the RPC call might look like this: +.ie t .DS +.el .DS L +.ft CW +char *arrptr; + +arrptr = NULL; +svc_getargs(transp, xdr_chararr2, &arrptr); +.ft I +/* + * Use the result here + */ +.ft CW +svc_freeargs(transp, xdr_chararr2, &arrptr); +.DE +Note that, after being used, the character array can be freed with +.I svc_freeargs() +.I svc_freeargs()  +will not attempt to free any memory if the variable indicating it  +is NULL.  For example, in the the routine  +.I xdr_finalexample (), +given earlier, if +.I finalp->string  +was NULL, then it would not be freed.  The same is true for  +.I finalp->simplep . +.LP +To summarize, each XDR routine is responsible +for serializing, deserializing, and freeing memory. +When an XDR routine is called from +.I callrpc() +the serializing part is used. +When called from +.I svc_getargs() +the deserializer is used. +And when called from +.I svc_freeargs() +the memory deallocator is used.  When building simple examples like those +in this section, a user doesn't have to worry  +about the three modes.   +See the +.I "External Data Representation: Sun Technical Notes" +for examples of more sophisticated XDR routines that determine  +which of the three modes they are in and adjust their behavior accordingly. +.KS +.NH 2 +\&The Calling Side +.IX RPC "calling side" +.LP +When you use +.I callrpc() +you have no control over the RPC delivery +mechanism or the socket used to transport the data. +To illustrate the layer of RPC that lets you adjust these +parameters, consider the following code to call the +.I nusers +service: +.ie t .DS +.el .DS L +.ft CW +.vs 11 +#include <stdio.h> +#include <rpc/rpc.h> +#include <utmp.h> +#include <rpcsvc/rusers.h> +#include <sys/socket.h> +#include <sys/time.h> +#include <netdb.h> + +main(argc, argv) +	int argc; +	char **argv; +{ +	struct hostent *hp; +	struct timeval pertry_timeout, total_timeout; +	struct sockaddr_in server_addr; +	int sock = RPC_ANYSOCK; +	register CLIENT *client; +	enum clnt_stat clnt_stat; +	unsigned long nusers; + +	if (argc != 2) { +		fprintf(stderr, "usage: nusers hostname\en"); +		exit(-1); +	} +	if ((hp = gethostbyname(argv[1])) == NULL) { +		fprintf(stderr, "can't get addr for %s\en",argv[1]); +		exit(-1); +	} +	pertry_timeout.tv_sec = 3; +	pertry_timeout.tv_usec = 0; +	bcopy(hp->h_addr, (caddr_t)&server_addr.sin_addr, +		hp->h_length); +	server_addr.sin_family = AF_INET; +	server_addr.sin_port =  0; +	if ((client = clntudp_create(&server_addr, RUSERSPROG, +	  RUSERSVERS, pertry_timeout, &sock)) == NULL) { +		clnt_pcreateerror("clntudp_create"); +		exit(-1); +	} +	total_timeout.tv_sec = 20; +	total_timeout.tv_usec = 0; +	clnt_stat = clnt_call(client, RUSERSPROC_NUM, xdr_void, +		0, xdr_u_long, &nusers, total_timeout); +	if (clnt_stat != RPC_SUCCESS) { +		clnt_perror(client, "rpc"); +		exit(-1); +	} +	clnt_destroy(client); +	close(sock); +	exit(0); +} +.vs +.DE +.KE +The low-level version of +.I callrpc() +is +.I clnt_call() +which takes a +.I CLIENT +pointer rather than a host name.  The parameters to +.I clnt_call()  +are a +.I CLIENT  +pointer, the procedure number, +the XDR routine for serializing the argument, +a pointer to the argument, +the XDR routine for deserializing the return value, +a pointer to where the return value will be placed, +and the time in seconds to wait for a reply. +.LP +The +.I CLIENT  +pointer is encoded with the transport mechanism. +.I callrpc() +uses UDP, thus it calls +.I clntudp_create()  +to get a +.I CLIENT  +pointer.  To get TCP (Transmission Control Protocol), you would use +.I clnttcp_create() . +.LP +The parameters to +.I clntudp_create()  +are the server address, the program number, the version number, +a timeout value (between tries), and a pointer to a socket. +The final argument to +.I clnt_call()  +is the total time to wait for a response. +Thus, the number of tries is the +.I clnt_call()  +timeout divided by the +.I clntudp_create()  +timeout. +.LP +Note that the +.I clnt_destroy() +call +always deallocates the space associated with the +.I CLIENT  +handle.  It closes the socket associated with the +.I CLIENT  +handle, however, only if the RPC library opened it.  It the +socket was opened by the user, it stays open.  This makes it +possible, in cases where there are multiple client handles +using the same socket, to destroy one handle without closing +the socket that other handles are using. +.LP +To make a stream connection, the call to +.I clntudp_create()  +is replaced with a call to +.I clnttcp_create() . +.DS +.ft CW +clnttcp_create(&server_addr, prognum, versnum, &sock, +               inputsize, outputsize); +.DE +There is no timeout argument; instead, the receive and send buffer +sizes must be specified.  When the +.I clnttcp_create()  +call is made, a TCP connection is established. +All RPC calls using that +.I CLIENT  +handle would use this connection. +The server side of an RPC call using TCP has +.I svcudp_create() +replaced by +.I svctcp_create() . +.DS +.ft CW +transp = svctcp_create(RPC_ANYSOCK, 0, 0); +.DE +The last two arguments to  +.I svctcp_create()  +are send and receive sizes respectively.  If `0' is specified for  +either of these, the system chooses a reasonable default. +.KS +.NH 1 +\&Other RPC Features +.IX "RPC" "miscellaneous features" +.IX "miscellaneous RPC features" +.LP +This section discusses some other aspects of RPC +that are occasionally useful. +.NH 2 +\&Select on the Server Side +.IX RPC select() RPC \fIselect()\fP +.IX select() "" \fIselect()\fP "on the server side" +.LP +Suppose a process is processing RPC requests +while performing some other activity. +If the other activity involves periodically updating a data structure, +the process can set an alarm signal before calling +.I svc_run() +But if the other activity +involves waiting on a a file descriptor, the +.I svc_run() +call won't work. +The code for +.I svc_run() +is as follows: +.ie t .DS +.el .DS L +.ft CW +.vs 11 +void +svc_run() +{ +	fd_set readfds; +	int dtbsz = getdtablesize(); + +	for (;;) { +		readfds = svc_fds; +		switch (select(dtbsz, &readfds, NULL,NULL,NULL)) { + +		case -1: +			if (errno == EINTR) +				continue; +			perror("select"); +			return; +		case 0: +			break; +		default: +			svc_getreqset(&readfds); +		} +	} +} +.vs +.DE +.KE +.LP +You can bypass +.I svc_run() +and call +.I svc_getreqset() +yourself. +All you need to know are the file descriptors +of the socket(s) associated with the programs you are waiting on. +Thus you can have your own +.I select()  +.IX select() "" \fIselect()\fP +that waits on both the RPC socket, +and your own descriptors.  Note that +.I svc_fds()  +is a bit mask of all the file descriptors that RPC is using for  +services.  It can change everytime that +.I any +RPC library routine is called, because descriptors are constantly  +being opened and closed, for example for TCP connections. +.NH 2 +\&Broadcast RPC +.IX "broadcast RPC" +.IX RPC "broadcast" +.LP +The +.I portmapper +is a daemon that converts RPC program numbers +into DARPA protocol port numbers; see the +.I portmap  +man page.  You can't do broadcast RPC without the portmapper. +Here are the main differences between +broadcast RPC and normal RPC calls: +.IP  1. +Normal RPC expects one answer, whereas +broadcast RPC expects many answers +(one or more answer from each responding machine). +.IP  2. +Broadcast RPC can only be supported by packet-oriented (connectionless) +transport protocols like UPD/IP. +.IP  3. +The implementation of broadcast RPC +treats all unsuccessful responses as garbage by filtering them out. +Thus, if there is a version mismatch between the +broadcaster and a remote service, +the user of broadcast RPC never knows. +.IP  4. +All broadcast messages are sent to the portmap port. +Thus, only services that register themselves with their portmapper +are accessible via the broadcast RPC mechanism. +.IP  5. +Broadcast requests are limited in size to the MTU (Maximum Transfer +Unit) of the local network.  For Ethernet, the MTU is 1500 bytes. +.KS +.NH 3 +\&Broadcast RPC Synopsis +.IX "broadcast RPC" synopsis +.IX "RPC" "broadcast synopsis" +.ie t .DS +.el .DS L +.ft CW +#include <rpc/pmap_clnt.h> +	. . . +enum clnt_stat	clnt_stat; +	. . . +clnt_stat = clnt_broadcast(prognum, versnum, procnum, +  inproc, in, outproc, out, eachresult) +	u_long    prognum;        /* \fIprogram number\fP */ +	u_long    versnum;        /* \fIversion number\fP */ +	u_long    procnum;        /* \fIprocedure number\fP */ +	xdrproc_t inproc;         /* \fIxdr routine for args\fP */ +	caddr_t   in;             /* \fIpointer to args\fP */ +	xdrproc_t outproc;        /* \fIxdr routine for results\fP */ +	caddr_t   out;            /* \fIpointer to results\fP */ +	bool_t    (*eachresult)();/* \fIcall with each result gotten\fP */ +.DE +.KE +The procedure +.I eachresult() +is called each time a valid result is obtained. +It returns a boolean that indicates +whether or not the user wants more responses. +.ie t .DS +.el .DS L +.ft CW +bool_t done; +	. . .  +done = eachresult(resultsp, raddr) +	caddr_t resultsp; +	struct sockaddr_in *raddr; /* \fIAddr of responding machine\fP */ +.DE +If +.I done +is +.I TRUE , +then broadcasting stops and +.I clnt_broadcast() +returns successfully. +Otherwise, the routine waits for another response. +The request is rebroadcast +after a few seconds of waiting. +If no responses come back, +the routine returns with +.I RPC_TIMEDOUT . +.NH 2 +\&Batching +.IX "batching" +.IX RPC "batching" +.LP +The RPC architecture is designed so that clients send a call message, +and wait for servers to reply that the call succeeded. +This implies that clients do not compute +while servers are processing a call. +This is inefficient if the client does not want or need +an acknowledgement for every message sent. +It is possible for clients to continue computing +while waiting for a response, +using RPC batch facilities. +.LP +RPC messages can be placed in a \*Qpipeline\*U of calls +to a desired server; this is called batching. +Batching assumes that: +1) each RPC call in the pipeline requires no response from the server, +and the server does not send a response message; and +2) the pipeline of calls is transported on a reliable +byte stream transport such as TCP/IP. +Since the server does not respond to every call, +the client can generate new calls in parallel +with the server executing previous calls. +Furthermore, the TCP/IP implementation can buffer up +many call messages, and send them to the server in one +.I write() +system call.  This overlapped execution +greatly decreases the interprocess communication overhead of +the client and server processes, +and the total elapsed time of a series of calls. +.LP +Since the batched calls are buffered, +the client should eventually do a nonbatched call +in order to flush the pipeline. +.LP +A contrived example of batching follows. +Assume a string rendering service (like a window system) +has two similar calls: one renders a string and returns void results, +while the other renders a string and remains silent. +The service (using the TCP/IP transport) may look like: +.ie t .DS +.el .DS L +.ft CW +#include <stdio.h> +#include <rpc/rpc.h> +#include <suntool/windows.h> + +void windowdispatch(); + +main() +{ +	SVCXPRT *transp; + +	transp = svctcp_create(RPC_ANYSOCK, 0, 0); +	if (transp == NULL){ +		fprintf(stderr, "can't create an RPC server\en"); +		exit(1); +	} +	pmap_unset(WINDOWPROG, WINDOWVERS); +	if (!svc_register(transp, WINDOWPROG, WINDOWVERS, +	  windowdispatch, IPPROTO_TCP)) { +		fprintf(stderr, "can't register WINDOW service\en"); +		exit(1); +	} +	svc_run();  /* \fINever returns\fP */ +	fprintf(stderr, "should never reach this point\en"); +} + +void +windowdispatch(rqstp, transp) +	struct svc_req *rqstp; +	SVCXPRT *transp; +{ +	char *s = NULL; + +	switch (rqstp->rq_proc) { +	case NULLPROC: +		if (!svc_sendreply(transp, xdr_void, 0))  +			fprintf(stderr, "can't reply to RPC call\en"); +		return; +	case RENDERSTRING: +		if (!svc_getargs(transp, xdr_wrapstring, &s)) { +			fprintf(stderr, "can't decode arguments\en"); +.ft I +			/* +			 * Tell caller he screwed up +			 */ +.ft CW +			svcerr_decode(transp); +			break; +		} +.ft I +		/* +		 * Code here to render the string \fIs\fP +		 */ +.ft CW +		if (!svc_sendreply(transp, xdr_void, NULL))  +			fprintf(stderr, "can't reply to RPC call\en"); +		break; +	case RENDERSTRING_BATCHED: +		if (!svc_getargs(transp, xdr_wrapstring, &s)) { +			fprintf(stderr, "can't decode arguments\en"); +.ft I +			/* +			 * We are silent in the face of protocol errors +			 */ +.ft CW +			break; +		} +.ft I +		/* +		 * Code here to render string s, but send no reply! +		 */ +.ft CW +		break; +	default: +		svcerr_noproc(transp); +		return; +	} +.ft I +	/* +	 * Now free string allocated while decoding arguments +	 */ +.ft CW +	svc_freeargs(transp, xdr_wrapstring, &s); +} +.DE +Of course the service could have one procedure +that takes the string and a boolean +to indicate whether or not the procedure should respond. +.LP +In order for a client to take advantage of batching, +the client must perform RPC calls on a TCP-based transport +and the actual calls must have the following attributes: +1) the result's XDR routine must be zero +.I NULL ), +and 2) the RPC call's timeout must be zero. +.KS +.LP +Here is an example of a client that uses batching to render a +bunch of strings; the batching is flushed when the client gets +a null string (EOF): +.ie t .DS +.el .DS L +.ft CW +.vs 11 +#include <stdio.h> +#include <rpc/rpc.h> +#include <sys/socket.h> +#include <sys/time.h> +#include <netdb.h> +#include <suntool/windows.h> + +main(argc, argv) +	int argc; +	char **argv; +{ +	struct hostent *hp; +	struct timeval pertry_timeout, total_timeout; +	struct sockaddr_in server_addr; +	int sock = RPC_ANYSOCK; +	register CLIENT *client; +	enum clnt_stat clnt_stat; +	char buf[1000], *s = buf; + +	if ((client = clnttcp_create(&server_addr, +	  WINDOWPROG, WINDOWVERS, &sock, 0, 0)) == NULL) { +		perror("clnttcp_create"); +		exit(-1); +	} +	total_timeout.tv_sec = 0; +	total_timeout.tv_usec = 0; +	while (scanf("%s", s) != EOF) { +		clnt_stat = clnt_call(client, RENDERSTRING_BATCHED, +			xdr_wrapstring, &s, NULL, NULL, total_timeout); +		if (clnt_stat != RPC_SUCCESS) { +			clnt_perror(client, "batched rpc"); +			exit(-1); +		} +	} + +	/* \fINow flush the pipeline\fP */ + +	total_timeout.tv_sec = 20; +	clnt_stat = clnt_call(client, NULLPROC, xdr_void, NULL, +		xdr_void, NULL, total_timeout); +	if (clnt_stat != RPC_SUCCESS) { +		clnt_perror(client, "rpc"); +		exit(-1); +	} +	clnt_destroy(client); +	exit(0); +} +.vs +.DE +.KE +Since the server sends no message, +the clients cannot be notified of any of the failures that may occur. +Therefore, clients are on their own when it comes to handling errors. +.LP +The above example was completed to render +all of the (2000) lines in the file +.I /etc/termcap . +The rendering service did nothing but throw the lines away. +The example was run in the following four configurations: +1) machine to itself, regular RPC; +2) machine to itself, batched RPC; +3) machine to another, regular RPC; and +4) machine to another, batched RPC. +The results are as follows: +1) 50 seconds; +2) 16 seconds; +3) 52 seconds; +4) 10 seconds. +Running +.I fscanf() +on +.I /etc/termcap +only requires six seconds. +These timings show the advantage of protocols +that allow for overlapped execution, +though these protocols are often hard to design. +.NH 2 +\&Authentication +.IX "authentication" +.IX "RPC" "authentication" +.LP +In the examples presented so far, +the caller never identified itself to the server, +and the server never required an ID from the caller. +Clearly, some network services, such as a network filesystem, +require stronger security than what has been presented so far. +.LP +In reality, every RPC call is authenticated by +the RPC package on the server, and similarly, +the RPC client package generates and sends authentication parameters. +Just as different transports (TCP/IP or UDP/IP) +can be used when creating RPC clients and servers, +different forms of authentication can be associated with RPC clients; +the default authentication type used as a default is type +.I none . +.LP +The authentication subsystem of the RPC package is open ended. +That is, numerous types of authentication are easy to support. +.NH 3 +\&UNIX Authentication +.IX "UNIX Authentication" +.IP "\fIThe Client Side\fP" +.LP +When a caller creates a new RPC client handle as in: +.DS +.ft CW +clnt = clntudp_create(address, prognum, versnum, +		      wait, sockp) +.DE +the appropriate transport instance defaults +the associate authentication handle to be +.DS +.ft CW +clnt->cl_auth = authnone_create(); +.DE +The RPC client can choose to use +.I UNIX +style authentication by setting +.I clnt\->cl_auth +after creating the RPC client handle: +.DS +.ft CW +clnt->cl_auth = authunix_create_default(); +.DE +This causes each RPC call associated with +.I clnt +to carry with it the following authentication credentials structure: +.ie t .DS +.el .DS L +.ft I +/* + * UNIX style credentials. + */ +.ft CW +struct authunix_parms { +    u_long  aup_time;       /* \fIcredentials creation time\fP */ +    char    *aup_machname;  /* \fIhost name where client is\fP */ +    int     aup_uid;        /* \fIclient's UNIX effective uid\fP */ +    int     aup_gid;        /* \fIclient's current group id\fP */ +    u_int   aup_len;        /* \fIelement length of aup_gids\fP */ +    int     *aup_gids;      /* \fIarray of groups user is in\fP */ +}; +.DE +These fields are set by +.I authunix_create_default() +by invoking the appropriate system calls. +Since the RPC user created this new style of authentication, +the user is responsible for destroying it with: +.DS +.ft CW +auth_destroy(clnt->cl_auth); +.DE +This should be done in all cases, to conserve memory. +.sp +.IP "\fIThe Server Side\fP" +.LP +Service implementors have a harder time dealing with authentication issues +since the RPC package passes the service dispatch routine a request +that has an arbitrary authentication style associated with it. +Consider the fields of a request handle passed to a service dispatch routine: +.ie t .DS +.el .DS L +.ft I +/* + * An RPC Service request + */ +.ft CW +struct svc_req { +    u_long    rq_prog;    	/* \fIservice program number\fP */ +    u_long    rq_vers;    	/* \fIservice protocol vers num\fP */ +    u_long    rq_proc;    	/* \fIdesired procedure number\fP */ +    struct opaque_auth rq_cred; /* \fIraw credentials from wire\fP */ +    caddr_t   rq_clntcred;  /* \fIcredentials (read only)\fP */ +}; +.DE +The +.I rq_cred +is mostly opaque, except for one field of interest: +the style or flavor of authentication credentials: +.ie t .DS +.el .DS L +.ft I +/* + * Authentication info.  Mostly opaque to the programmer. + */ +.ft CW +struct opaque_auth { +    enum_t  oa_flavor;  /* \fIstyle of credentials\fP */ +    caddr_t oa_base;    /* \fIaddress of more auth stuff\fP */ +    u_int   oa_length;  /* \fInot to exceed \fIMAX_AUTH_BYTES */ +}; +.DE +.IX RPC guarantees +The RPC package guarantees the following +to the service dispatch routine: +.IP  1. +That the request's +.I rq_cred +is well formed.  Thus the service implementor may inspect the request's +.I rq_cred.oa_flavor +to determine which style of authentication the caller used. +The service implementor may also wish to inspect the other fields of +.I rq_cred +if the style is not one of the styles supported by the RPC package. +.IP  2. +That the request's +.I rq_clntcred +field is either +.I NULL  +or points to a well formed structure +that corresponds to a supported style of authentication credentials. +Remember that only +.I unix +style is currently supported, so (currently) +.I rq_clntcred +could be cast to a pointer to an +.I authunix_parms +structure.  If +.I rq_clntcred +is +.I NULL , +the service implementor may wish to inspect the other (opaque) fields of +.I rq_cred +in case the service knows about a new type of authentication +that the RPC package does not know about. +.LP +Our remote users service example can be extended so that +it computes results for all users except UID 16: +.ie t .DS +.el .DS L +.ft CW +.vs 11 +nuser(rqstp, transp) +	struct svc_req *rqstp; +	SVCXPRT *transp; +{ +	struct authunix_parms *unix_cred; +	int uid; +	unsigned long nusers; + +.ft I +	/* +	 * we don't care about authentication for null proc +	 */ +.ft CW +	if (rqstp->rq_proc == NULLPROC) { +		if (!svc_sendreply(transp, xdr_void, 0)) { +			fprintf(stderr, "can't reply to RPC call\en"); +			return (1); +		 } +		 return; +	} +.ft I +	/* +	 * now get the uid +	 */ +.ft CW +	switch (rqstp->rq_cred.oa_flavor) { +	case AUTH_UNIX: +		unix_cred =  +			(struct authunix_parms *)rqstp->rq_clntcred; +		uid = unix_cred->aup_uid; +		break; +	case AUTH_NULL: +	default: +		svcerr_weakauth(transp); +		return; +	} +	switch (rqstp->rq_proc) { +	case RUSERSPROC_NUM: +.ft I +		/* +		 * make sure caller is allowed to call this proc +		 */ +.ft CW +		if (uid == 16) { +			svcerr_systemerr(transp); +			return; +		} +.ft I +		/* +		 * Code here to compute the number of users +		 * and assign it to the variable \fInusers\fP +		 */ +.ft CW +		if (!svc_sendreply(transp, xdr_u_long, &nusers)) { +			fprintf(stderr, "can't reply to RPC call\en"); +			return (1); +		} +		return; +	default: +		svcerr_noproc(transp); +		return; +	} +} +.vs +.DE +A few things should be noted here. +First, it is customary not to check +the authentication parameters associated with the +.I NULLPROC +(procedure number zero). +Second, if the authentication parameter's type is not suitable +for your service, you should call +.I svcerr_weakauth() . +And finally, the service protocol itself should return status +for access denied; in the case of our example, the protocol +does not have such a status, so we call the service primitive +.I svcerr_systemerr() +instead. +.LP +The last point underscores the relation between +the RPC authentication package and the services; +RPC deals only with  +.I authentication  +and not with individual services'  +.I "access control" . +The services themselves must implement their own access control policies +and reflect these policies as return statuses in their protocols. +.NH 2 +\&DES Authentication +.IX RPC DES +.IX RPC authentication +.LP +UNIX authentication is quite easy to defeat.  Instead of using +.I authunix_create_default (), +one can call +.I authunix_create()  +and then modify the RPC authentication handle it returns by filling in +whatever user ID and hostname they wish the server to think they have. +DES authentication is thus recommended for people who want more security +than UNIX authentication offers. +.LP +The details of the DES authentication protocol are complicated and +are not explained here.   +See +.I "Remote Procedure Calls: Protocol Specification" +for the details. +.LP +In  order for  DES authentication   to  work, the +.I keyserv(8c)  +daemon must be running  on both  the  server  and client machines.  The +users on  these machines  need  public  keys  assigned by  the network +administrator in  the +.I publickey(5)  +database.  And,  they  need to have decrypted  their  secret keys +using  their  login   password.  This automatically happens when one +logs in using +.I login(1) , +or can be done manually using +.I keylogin(1) . +The +.I "Network Services" +chapter +./" XXX +explains more how to setup secure networking. +.sp +.IP "\fIClient Side\fP" +.LP +If a client wishes to use DES authentication, it must set its +authentication handle appropriately.  Here is an example: +.DS +cl->cl_auth = +	authdes_create(servername, 60, &server_addr, NULL); +.DE +The first argument is the network name or \*Qnetname\*U of the owner of +the server process.  Typically, server processes are root processes +and their netname can be derived using the following call: +.DS +char servername[MAXNETNAMELEN]; + +host2netname(servername, rhostname, NULL); +.DE +Here, +.I rhostname +is the hostname of the machine the server process is running on. +.I host2netname()  +fills in +.I servername +to contain this root process's netname.  If the +server process was run by a regular user, one could use the call +.I user2netname()  +instead.  Here is an example for a server process with the same user +ID as the client: +.DS +char servername[MAXNETNAMELEN]; + +user2netname(servername, getuid(), NULL); +.DE +The last argument to both of these calls, +.I user2netname()  +and +.I host2netname (), +is the name of the naming domain where the server is located.  The +.I NULL  +used here means \*Quse the local domain name.\*U +.LP +The second argument to +.I authdes_create()  +is a lifetime for the credential.  Here it is set to sixty +seconds.  What that means is that the credential will expire 60 +seconds from now.  If some mischievous user tries to reuse the +credential, the server RPC subsystem will recognize that it has +expired and not grant any requests.  If the same mischievous user +tries to reuse the credential within the sixty second lifetime, +he will still be rejected because the server RPC subsystem +remembers which credentials it has already seen in the near past, +and will not grant requests to duplicates. +.LP +The third argument to +.I authdes_create()  +is the address of the host to synchronize with.  In order for DES +authentication to work, the server and client must agree upon the +time.  Here we pass the address of the server itself, so the +client and server will both be using the same time: the server's +time.  The argument can be +.I NULL , +which means \*Qdon't bother synchronizing.\*U You should only do this +if you are sure the client and server are already synchronized. +.LP +The final argument to +.I authdes_create()  +is the address of a DES encryption key to use for encrypting +timestamps and data.  If this argument is +.I NULL , +as it is in this example, a random key will be chosen.  The client +may find out the encryption key being used by consulting the +.I ah_key  +field of the authentication handle. +.sp +.IP "\fIServer Side\fP" +.LP +The server side is a lot simpler than the client side.  Here is the +previous example rewritten to use +.I AUTH_DES +instead of +.I AUTH_UNIX : +.ie t .DS +.el .DS L +.ft CW +.vs 11 +#include <sys/time.h> +#include <rpc/auth_des.h> +	. . . +	. . . +nuser(rqstp, transp) +	struct svc_req *rqstp; +	SVCXPRT *transp; +{ +	struct authdes_cred *des_cred; +	int uid; +	int gid; +	int gidlen; +	int gidlist[10]; +.ft I +	/* +	 * we don't care about authentication for null proc +	 */ +.ft CW + +	if (rqstp->rq_proc == NULLPROC) {  +		/* \fIsame as before\fP */ +	} + +.ft I +	/* +	 * now get the uid +	 */ +.ft CW +	switch (rqstp->rq_cred.oa_flavor) { +	case AUTH_DES: +		des_cred = +			(struct authdes_cred *) rqstp->rq_clntcred; +		if (! netname2user(des_cred->adc_fullname.name, +			&uid, &gid, &gidlen, gidlist)) +		{ +			fprintf(stderr, "unknown user: %s\n", +				des_cred->adc_fullname.name); +			svcerr_systemerr(transp); +			return; +		} +		break; +	case AUTH_NULL: +	default: +		svcerr_weakauth(transp); +		return; +	} + +.ft I +	/* +	 * The rest is the same as before + 	 */	 +.ft CW +.vs +.DE +Note the use of the routine +.I netname2user (), +the inverse of +.I user2netname (): +it takes a network ID and converts to a unix ID. +.I netname2user ()  +also supplies the group IDs which we don't use in this example, +but which may be useful to other UNIX programs. +.NH 2 +\&Using Inetd +.IX inetd "" "using \fIinetd\fP" +.LP +An RPC server can be started from +.I inetd +The only difference from the usual code is that the service +creation routine should be called in the following form: +.ie t .DS +.el .DS L +.ft CW +transp = svcudp_create(0);     /* \fIFor UDP\fP */ +transp = svctcp_create(0,0,0); /* \fIFor listener TCP sockets\fP */ +transp = svcfd_create(0,0,0);  /* \fIFor connected TCP sockets\fP */ +.DE +since +.I inet +passes a socket as file descriptor 0. +Also, +.I svc_register() +should be called as +.ie t .DS +.el .DS L +.ft CW +svc_register(transp, PROGNUM, VERSNUM, service, 0); +.DE +with the final flag as 0, +since the program would already be registered by +.I inetd +Remember that if you want to exit +from the server process and return control to +.I inet +you need to explicitly exit, since +.I svc_run() +never returns. +.LP +The format of entries in  +.I /etc/inetd.conf  +for RPC services is in one of the following two forms: +.ie t .DS +.el .DS L +.ft CW +p_name/version dgram  rpc/udp wait/nowait user server args +p_name/version stream rpc/tcp wait/nowait user server args +.DE +where +.I p_name +is the symbolic name of the program as it appears in +.I rpc(5) , +.I server +is the program implementing the server, +and +.I program +and +.I version +are the program and version numbers of the service. +For more information, see +.I inetd.conf(5) . +.LP +If the same program handles multiple versions, +then the version number can be a range, +as in this example: +.ie t .DS +.el .DS L +.ft CW +rstatd/1-2 dgram rpc/udp wait root /usr/etc/rpc.rstatd +.DE +.NH 1 +\&More Examples +.sp 1 +.NH 2 +\&Versions +.IX "versions" +.IX "RPC" "versions" +.LP +By convention, the first version number of program +.I PROG +is +.I PROGVERS_ORIG +and the most recent version is +.I PROGVERS +Suppose there is a new version of the +.I user +program that returns an +.I "unsigned short" +rather than a +.I long . +If we name this version +.I RUSERSVERS_SHORT +then a server that wants to support both versions +would do a double register. +.ie t .DS +.el .DS L +.ft CW +if (!svc_register(transp, RUSERSPROG, RUSERSVERS_ORIG, +  nuser, IPPROTO_TCP)) { +	fprintf(stderr, "can't register RUSER service\en"); +	exit(1); +} +if (!svc_register(transp, RUSERSPROG, RUSERSVERS_SHORT, +  nuser, IPPROTO_TCP)) { +	fprintf(stderr, "can't register RUSER service\en"); +	exit(1); +} +.DE +Both versions can be handled by the same C procedure: +.ie t .DS +.el .DS L +.ft CW +.vs 11 +nuser(rqstp, transp) +	struct svc_req *rqstp; +	SVCXPRT *transp; +{ +	unsigned long nusers; +	unsigned short nusers2; + +	switch (rqstp->rq_proc) { +	case NULLPROC: +		if (!svc_sendreply(transp, xdr_void, 0)) { +			fprintf(stderr, "can't reply to RPC call\en"); +            return (1); +		} +		return; +	case RUSERSPROC_NUM: +.ft I +		/* +         * Code here to compute the number of users +         * and assign it to the variable \fInusers\fP +		 */ +.ft CW +		nusers2 = nusers; +		switch (rqstp->rq_vers) { +		case RUSERSVERS_ORIG: +            if (!svc_sendreply(transp, xdr_u_long,  +		    &nusers)) { +                fprintf(stderr,"can't reply to RPC call\en"); +			} +			break; +		case RUSERSVERS_SHORT: +            if (!svc_sendreply(transp, xdr_u_short,  +		    &nusers2)) { +                fprintf(stderr,"can't reply to RPC call\en"); +			} +			break; +		} +	default: +		svcerr_noproc(transp); +		return; +	} +} +.vs +.DE +.KS +.NH 2 +\&TCP +.IX "TCP" +.LP +Here is an example that is essentially +.I rcp. +The initiator of the RPC +.I snd +call takes its standard input and sends it to the server +.I rcv +which prints it on standard output. +The RPC call uses TCP. +This also illustrates an XDR procedure that behaves differently +on serialization than on deserialization. +.ie t .DS +.el .DS L +.vs 11 +.ft I +/* + * The xdr routine: + *		on decode, read from wire, write onto fp + *		on encode, read from fp, write onto wire + */ +.ft CW +#include <stdio.h> +#include <rpc/rpc.h> + +xdr_rcp(xdrs, fp) +	XDR *xdrs; +	FILE *fp; +{ +	unsigned long size; +	char buf[BUFSIZ], *p; + +	if (xdrs->x_op == XDR_FREE)/* nothing to free */ +		return 1; +	while (1) { +		if (xdrs->x_op == XDR_ENCODE) { +			if ((size = fread(buf, sizeof(char), BUFSIZ, +			  fp)) == 0 && ferror(fp)) { +				fprintf(stderr, "can't fread\en"); +				return (1); +			} +		} +		p = buf; +		if (!xdr_bytes(xdrs, &p, &size, BUFSIZ)) +			return 0; +		if (size == 0) +			return 1; +		if (xdrs->x_op == XDR_DECODE) { +			if (fwrite(buf, sizeof(char), size, +			  fp) != size) { +				fprintf(stderr, "can't fwrite\en"); +				return (1); +			} +		} +	} +} +.vs +.DE +.KE +.ie t .DS +.el .DS L +.vs 11 +.ft I +/* + * The sender routines + */ +.ft CW +#include <stdio.h> +#include <netdb.h> +#include <rpc/rpc.h> +#include <sys/socket.h> +#include <sys/time.h> + +main(argc, argv) +	int argc; +	char **argv; +{ +	int xdr_rcp(); +	int err; + +	if (argc < 2) { +		fprintf(stderr, "usage: %s servername\en", argv[0]); +		exit(-1); +	} +	if ((err = callrpctcp(argv[1], RCPPROG, RCPPROC, +	  RCPVERS, xdr_rcp, stdin, xdr_void, 0) != 0)) { +		clnt_perrno(err); +		fprintf(stderr, "can't make RPC call\en"); +		exit(1); +	} +	exit(0); +} + +callrpctcp(host, prognum, procnum, versnum, +           inproc, in, outproc, out) +	char *host, *in, *out; +	xdrproc_t inproc, outproc; +{ +	struct sockaddr_in server_addr; +	int socket = RPC_ANYSOCK; +	enum clnt_stat clnt_stat; +	struct hostent *hp; +	register CLIENT *client; +	struct timeval total_timeout; + +	if ((hp = gethostbyname(host)) == NULL) { +		fprintf(stderr, "can't get addr for '%s'\en", host); +		return (-1); +	} +	bcopy(hp->h_addr, (caddr_t)&server_addr.sin_addr, +		hp->h_length); +	server_addr.sin_family = AF_INET; +	server_addr.sin_port =  0; +	if ((client = clnttcp_create(&server_addr, prognum, +	  versnum, &socket, BUFSIZ, BUFSIZ)) == NULL) { +		perror("rpctcp_create"); +		return (-1); +	} +	total_timeout.tv_sec = 20; +	total_timeout.tv_usec = 0; +	clnt_stat = clnt_call(client, procnum, +		inproc, in, outproc, out, total_timeout); +	clnt_destroy(client); +	return (int)clnt_stat; +} +.vs +.DE +.ie t .DS +.el .DS L +.vs 11 +.ft I +/* + * The receiving routines + */ +.ft CW +#include <stdio.h> +#include <rpc/rpc.h> + +main() +{ +	register SVCXPRT *transp; +     int rcp_service(), xdr_rcp();  + +	if ((transp = svctcp_create(RPC_ANYSOCK, +	  BUFSIZ, BUFSIZ)) == NULL) { +		fprintf("svctcp_create: error\en"); +		exit(1); +	} +	pmap_unset(RCPPROG, RCPVERS); +	if (!svc_register(transp, +	  RCPPROG, RCPVERS, rcp_service, IPPROTO_TCP)) { +		fprintf(stderr, "svc_register: error\en"); +		exit(1); +	} +	svc_run();  /* \fInever returns\fP */ +	fprintf(stderr, "svc_run should never return\en"); +} + +rcp_service(rqstp, transp) +	register struct svc_req *rqstp; +	register SVCXPRT *transp; +{ +	switch (rqstp->rq_proc) { +	case NULLPROC: +		if (svc_sendreply(transp, xdr_void, 0) == 0) { +			fprintf(stderr, "err: rcp_service"); +			return (1); +		} +		return; +	case RCPPROC_FP: +		if (!svc_getargs(transp, xdr_rcp, stdout)) { +			svcerr_decode(transp); +			return; +		} +		if (!svc_sendreply(transp, xdr_void, 0)) { +			fprintf(stderr, "can't reply\en"); +			return; +		} +		return (0); +	default: +		svcerr_noproc(transp); +		return; +	} +} +.vs +.DE +.NH 2 +\&Callback Procedures +.IX RPC "callback procedures" +.LP +Occasionally, it is useful to have a server become a client, +and make an RPC call back to the process which is its client. +An example is remote debugging, +where the client is a window system program, +and the server is a debugger running on the remote machine. +Most of the time, +the user clicks a mouse button at the debugging window, +which converts this to a debugger command, +and then makes an RPC call to the server +(where the debugger is actually running), +telling it to execute that command. +However, when the debugger hits a breakpoint, the roles are reversed, +and the debugger wants to make an rpc call to the window program, +so that it can inform the user that a breakpoint has been reached. +.LP +In order to do an RPC callback, +you need a program number to make the RPC call on. +Since this will be a dynamically generated program number, +it should be in the transient range, +.I "0x40000000 - 0x5fffffff" . +The routine +.I gettransient() +returns a valid program number in the transient range, +and registers it with the portmapper. +It only talks to the portmapper running on the same machine as the +.I gettransient() +routine itself.  The call to +.I pmap_set() +is a test and set operation, +in that it indivisibly tests whether a program number +has already been registered, +and if it has not, then reserves it.  On return, the +.I sockp +argument will contain a socket that can be used +as the argument to an +.I svcudp_create() +or +.I svctcp_create() +call. +.ie t .DS +.el .DS L +.ft CW +.vs 11 +#include <stdio.h> +#include <rpc/rpc.h> +#include <sys/socket.h> + +gettransient(proto, vers, sockp) +	int proto, vers, *sockp; +{ +	static int prognum = 0x40000000; +	int s, len, socktype; +	struct sockaddr_in addr; + +	switch(proto) { +		case IPPROTO_UDP: +			socktype = SOCK_DGRAM; +			break; +		case IPPROTO_TCP: +			socktype = SOCK_STREAM; +			break; +		default: +			fprintf(stderr, "unknown protocol type\en"); +			return 0; +	} +	if (*sockp == RPC_ANYSOCK) { +		if ((s = socket(AF_INET, socktype, 0)) < 0) { +			perror("socket"); +			return (0); +		} +		*sockp = s; +	} +	else +		s = *sockp; +	addr.sin_addr.s_addr = 0; +	addr.sin_family = AF_INET; +	addr.sin_port = 0; +	len = sizeof(addr); +.ft I +	/* +	 * may be already bound, so don't check for error +	 */ +.ft CW +	bind(s, &addr, len); +	if (getsockname(s, &addr, &len)< 0) { +		perror("getsockname"); +		return (0); +	} +	while (!pmap_set(prognum++, vers, proto,  +		ntohs(addr.sin_port))) continue; +	return (prognum-1); +} +.vs +.DE +.SH +Note: +.I +The call to +.I ntohs()  +is necessary to ensure that the port number in +.I "addr.sin_port" , +which is in  +.I network  +byte order, is passed in  +.I host +byte order (as +.I pmap_set()  +expects).  See the +.I byteorder(3N)  +man page for more details on the conversion of network +addresses from network to host byte order. +.KS +.LP +The following pair of programs illustrate how to use the +.I gettransient() +routine. +The client makes an RPC call to the server, +passing it a transient program number. +Then the client waits around to receive a callback +from the server at that program number. +The server registers the program +.I EXAMPLEPROG +so that it can receive the RPC call +informing it of the callback program number. +Then at some random time (on receiving an +.I ALRM +signal in this example), it sends a callback RPC call, +using the program number it received earlier. +.ie t .DS +.el .DS L +.vs 11 +.ft I +/* + * client + */ +.ft CW +#include <stdio.h> +#include <rpc/rpc.h> + +int callback(); +char hostname[256]; + +main() +{ +	int x, ans, s; +	SVCXPRT *xprt; + +	gethostname(hostname, sizeof(hostname)); +	s = RPC_ANYSOCK; +	x = gettransient(IPPROTO_UDP, 1, &s); +	fprintf(stderr, "client gets prognum %d\en", x); +	if ((xprt = svcudp_create(s)) == NULL) { +	  fprintf(stderr, "rpc_server: svcudp_create\en"); +		exit(1); +	} +.ft I +	/* protocol is 0 - gettransient does registering +	 */ +.ft CW +	(void)svc_register(xprt, x, 1, callback, 0); +	ans = callrpc(hostname, EXAMPLEPROG, EXAMPLEVERS, +		EXAMPLEPROC_CALLBACK, xdr_int, &x, xdr_void, 0); +	if ((enum clnt_stat) ans != RPC_SUCCESS) { +		fprintf(stderr, "call: "); +		clnt_perrno(ans); +		fprintf(stderr, "\en"); +	} +	svc_run(); +	fprintf(stderr, "Error: svc_run shouldn't return\en"); +} + +callback(rqstp, transp) +	register struct svc_req *rqstp; +	register SVCXPRT *transp; +{ +	switch (rqstp->rq_proc) { +		case 0: +			if (!svc_sendreply(transp, xdr_void, 0)) { +				fprintf(stderr, "err: exampleprog\en"); +				return (1); +			} +			return (0); +		case 1: +			if (!svc_getargs(transp, xdr_void, 0)) { +				svcerr_decode(transp); +				return (1); +			} +			fprintf(stderr, "client got callback\en"); +			if (!svc_sendreply(transp, xdr_void, 0)) { +				fprintf(stderr, "err: exampleprog"); +				return (1); +			} +	} +} +.vs +.DE +.KE +.ie t .DS +.el .DS L +.vs 11 +.ft I +/* + * server + */ +.ft CW +#include <stdio.h> +#include <rpc/rpc.h> +#include <sys/signal.h> + +char *getnewprog(); +char hostname[256]; +int docallback(); +int pnum;		/* \fIprogram number for callback routine\fP */ + +main() +{ +	gethostname(hostname, sizeof(hostname)); +	registerrpc(EXAMPLEPROG, EXAMPLEVERS, +	  EXAMPLEPROC_CALLBACK, getnewprog, xdr_int, xdr_void); +	fprintf(stderr, "server going into svc_run\en"); +	signal(SIGALRM, docallback); +	alarm(10); +	svc_run(); +	fprintf(stderr, "Error: svc_run shouldn't return\en"); +} + +char * +getnewprog(pnump) +	char *pnump; +{ +	pnum = *(int *)pnump; +	return NULL; +} + +docallback() +{ +	int ans; + +	ans = callrpc(hostname, pnum, 1, 1, xdr_void, 0, +		xdr_void, 0); +	if (ans != 0) { +		fprintf(stderr, "server: "); +		clnt_perrno(ans); +		fprintf(stderr, "\en"); +	} +} +.vs +.DE diff --git a/lib/librpc/doc/rpc.rfc.ms b/lib/librpc/doc/rpc.rfc.ms new file mode 100644 index 000000000000..af9c2df2ed83 --- /dev/null +++ b/lib/librpc/doc/rpc.rfc.ms @@ -0,0 +1,1302 @@ +.\" +.\" Must use  --  tbl  --  with this one +.\" +.\" @(#)rpc.rfc.ms	2.2 88/08/05 4.0 RPCSRC +.de BT +.if \\n%=1 .tl ''- % -'' +.. +.ND +.\" prevent excess underlining in nroff +.if n .fp 2 R +.OH 'Remote Procedure Calls: Protocol Specification''Page %' +.EH 'Page %''Remote Procedure Calls: Protocol Specification' +.if \\n%=1 .bp +.SH +\&Remote Procedure Calls: Protocol Specification +.LP +.NH 0 +\&Status of this Memo +.LP +Note: This chapter specifies a protocol that Sun Microsystems, Inc., +and others are using.   +It has been designated RFC1050 by the ARPA Network +Information Center. +.LP +.NH 1 +\&Introduction +.LP +This chapter specifies  a  message protocol  used in implementing +Sun's Remote Procedure Call (RPC) package.  (The message protocol is +specified with the External Data Representation (XDR) language. +See the +.I "External Data Representation Standard: Protocol Specification" +for the details.  Here, we assume that  the  reader is familiar   +with XDR and do not attempt to justify it or its uses).  The paper +by Birrell and Nelson [1]  is recommended as an  excellent background +to  and justification of RPC. +.NH 2 +\&Terminology +.LP +This chapter discusses servers, services, programs, procedures, +clients, and versions.  A server is a piece of software where network +services are implemented.  A network service is a collection of one +or more remote programs.  A remote program implements one or more +remote procedures; the procedures, their parameters, and results are +documented in the specific program's protocol specification (see the +\fIPort Mapper Program Protocol\fP\, below, for an example).  Network +clients are pieces of software that initiate remote procedure calls +to services.  A server may support more than one version of a remote +program in order to be forward compatible with changing protocols. +.LP +For example, a network file service may be composed of two programs. +One program may deal with high-level applications such as file system +access control and locking.  The other may deal with low-level file +IO and have procedures like "read" and "write".  A client machine of +the network file service would call the procedures associated with +the two programs of the service on behalf of some user on the client +machine. +.NH 2 +\&The RPC Model +.LP +The remote procedure call model is similar to the local procedure +call model.  In the local case, the caller places arguments to a +procedure in some well-specified location (such as a result +register).  It then transfers control to the procedure, and +eventually gains back control.  At that point, the results of the +procedure are extracted from the well-specified location, and the +caller continues execution. +.LP +The remote procedure call is similar, in that one thread of control +logically winds through two processes\(emone is the caller's process, +the other is a server's process.  That is, the caller process sends a +call message to the server process and waits (blocks) for a reply +message.  The call message contains the procedure's parameters, among +other things.  The reply message contains the procedure's results, +among other things.  Once the reply message is received, the results +of the procedure are extracted, and caller's execution is resumed. +.LP +On the server side, a process is dormant awaiting the arrival of a +call message.  When one arrives, the server process extracts the +procedure's parameters, computes the results, sends a reply message, +and then awaits the next call message. +.LP +Note that in this model, only one of the two processes is active at +any given time.  However, this model is only given as an example. +The RPC protocol makes no restrictions on the concurrency model +implemented, and others are possible.  For example, an implementation +may choose to have RPC calls be asynchronous, so that the client may +do useful work while waiting for the reply from the server.  Another +possibility is to have the server create a task to process an +incoming request, so that the server can be free to receive other +requests. +.NH 2 +\&Transports and Semantics +.LP +The RPC protocol is independent of transport protocols.  That is, RPC +does not care how a message is passed from one process to another. +The protocol deals only with specification and interpretation of +messages. +.LP +It is important to point out that RPC does not try to implement any +kind of reliability and that the application must be aware of the +type of transport protocol underneath RPC.  If it knows it is running +on top of a reliable transport such as TCP/IP[6], then most of the +work is already done for it.  On the other hand, if it is running on +top of an unreliable transport such as UDP/IP[7], it must implement +is own retransmission and time-out policy as the RPC layer does not +provide this service. +.LP +Because of transport independence, the RPC protocol does not attach +specific semantics to the remote procedures or their execution. +Semantics can be inferred from (but should be explicitly specified +by) the underlying transport protocol.  For example, consider RPC +running on top of an unreliable transport such as UDP/IP.  If an +application retransmits RPC messages after short time-outs, the only +thing it can infer if it receives no reply is that the procedure was +executed zero or more times.  If it does receive a reply, then it can +infer that the procedure was executed at least once. +.LP +A server may wish to remember previously granted requests from a +client and not regrant them in order to insure some degree of +execute-at-most-once semantics.  A server can do this by taking +advantage of the transaction ID that is packaged with every RPC +request.  The main use of this transaction is by the client RPC layer +in matching replies to requests.  However, a client application may +choose to reuse its previous transaction ID when retransmitting a +request.  The server application, knowing this fact, may choose to +remember this ID after granting a request and not regrant requests +with the same ID in order to achieve some degree of +execute-at-most-once semantics.  The server is not allowed to examine +this ID in any other way except as a test for equality. +.LP +On the other hand, if using a reliable transport such as TCP/IP, the +application can infer from a reply message that the procedure was +executed exactly once, but if it receives no reply message, it cannot +assume the remote procedure was not executed.  Note that even if a +connection-oriented protocol like TCP is used, an application still +needs time-outs and reconnection to handle server crashes. +.LP +There are other possibilities for transports besides datagram- or +connection-oriented protocols.  For example, a request-reply protocol +such as VMTP[2] is perhaps the most natural transport for RPC. +.SH +.I +NOTE:  At Sun, RPC is currently implemented on top of both TCP/IP +and UDP/IP transports. +.LP +.NH 2 +\&Binding and Rendezvous Independence +.LP +The act of binding a client to a service is NOT part of the remote +procedure call specification.  This important and necessary function +is left up to some higher-level software.  (The software may use RPC +itself\(emsee the \fIPort Mapper Program Protocol\fP\, below). +.LP +Implementors should think of the RPC protocol as the jump-subroutine +instruction ("JSR") of a network; the loader (binder) makes JSR +useful, and the loader itself uses JSR to accomplish its task. +Likewise, the network makes RPC useful, using RPC to accomplish this +task. +.NH 2 +\&Authentication +.LP +The RPC protocol provides the fields necessary for a client to +identify itself to a service and vice-versa.  Security and access +control mechanisms can be built on top of the message authentication. +Several different authentication protocols can be supported.  A field +in the RPC header indicates which protocol is being used.  More +information on specific authentication protocols can be found in the +\fIAuthentication Protocols\fP\, +below. +.KS +.NH 1 +\&RPC Protocol Requirements +.LP +The RPC protocol must provide for the following: +.IP  1. +Unique specification of a procedure to be called. +.IP  2. +Provisions for matching response messages to request messages. +.KE +.IP  3. +Provisions for authenticating the caller to service and vice-versa. +.LP +Besides these requirements, features that detect the following are +worth supporting because of protocol roll-over errors, implementation +bugs, user error, and network administration: +.IP  1. +RPC protocol mismatches. +.IP  2. +Remote program protocol version mismatches. +.IP  3. +Protocol errors (such as misspecification of a procedure's parameters). +.IP  4. +Reasons why remote authentication failed. +.IP  5. +Any other reasons why the desired procedure was not called. +.NH 2 +\&Programs and Procedures +.LP +The RPC call message has three unsigned fields:  remote program +number, remote program version number, and remote procedure number. +The three fields uniquely identify the procedure to be called. +Program numbers are administered by some central authority (like +Sun).  Once an implementor has a program number, he can implement his +remote program; the first implementation would most likely have the +version number of 1.  Because most new protocols evolve into better, +stable, and mature protocols, a version field of the call message +identifies which version of the protocol the caller is using. +Version numbers make speaking old and new protocols through the same +server process possible. +.LP +The procedure number identifies the procedure to be called.  These +numbers are documented in the specific program's protocol +specification.  For example, a file service's protocol specification +may state that its procedure number 5 is "read" and procedure number +12 is "write". +.LP +Just as remote program protocols may change over several versions, +the actual RPC message protocol could also change.  Therefore, the +call message also has in it the RPC version number, which is always +equal to two for the version of RPC described here. +.LP +The reply message to a request  message  has enough  information to +distinguish the following error conditions: +.IP  1. +The remote implementation of RPC does speak protocol version 2. +The lowest and highest supported RPC version numbers are returned. +.IP  2. +The remote program is not available on the remote system. +.IP  3. +The remote program does not support the requested version number. +The lowest and highest supported remote program version numbers are +returned. +.IP  4. +The requested procedure number does not exist.  (This is usually a +caller side protocol or programming error.) +.IP  5. +The parameters to the remote procedure appear to be garbage from the +server's point of view.  (Again, this is usually caused by a +disagreement about the protocol between client and service.) +.NH 2 +\&Authentication +.LP +Provisions for authentication of caller to service and vice-versa are +provided as a part of the RPC protocol.  The call message has two +authentication fields, the credentials and verifier.  The reply +message has one authentication field, the response verifier.  The RPC +protocol specification defines all three fields to be the following +opaque type: +.DS +.ft CW +.vs 11 +enum auth_flavor { +    AUTH_NULL        = 0, +    AUTH_UNIX        = 1, +    AUTH_SHORT       = 2, +    AUTH_DES         = 3 +    /* \fIand more to be defined\fP */ +}; + +struct opaque_auth { +    auth_flavor flavor; +    opaque body<400>; +}; +.DE +.LP +In simple English, any +.I opaque_auth  +structure is an  +.I auth_flavor  +enumeration followed by bytes which are  opaque to the RPC protocol +implementation. +.LP +The interpretation and semantics  of the data contained  within the +authentication   fields  is specified  by  individual,  independent +authentication  protocol specifications.   (See  +\fIAuthentication Protocols\fP\, +below, for definitions of the various authentication protocols.) +.LP +If authentication parameters were   rejected, the  response message +contains information stating why they were rejected. +.NH 2 +\&Program Number Assignment +.LP +Program numbers are given out in groups of +.I 0x20000000  +(decimal 536870912) according to the following chart: +.TS +box tab (&) ; +lfI lfI +rfL cfI . +Program Numbers&Description +_ +.sp .5 +0 - 1fffffff&Defined by Sun +20000000 - 3fffffff&Defined by user +40000000 - 5fffffff&Transient +60000000 - 7fffffff&Reserved +80000000 - 9fffffff&Reserved +a0000000 - bfffffff&Reserved +c0000000 - dfffffff&Reserved +e0000000 - ffffffff&Reserved +.TE +.LP +The first group is a range of numbers administered by Sun +Microsystems and should be identical for all sites.  The second range +is for applications peculiar to a particular site.  This range is +intended primarily for debugging new programs.  When a site develops +an application that might be of general interest, that application +should be given an assigned number in the first range.  The third +group is for applications that generate program numbers dynamically. +The final groups are reserved for future use, and should not be used. +.NH 2 +\&Other Uses of the RPC Protocol +.LP +The intended use of this protocol is for calling remote procedures. +That is, each call message is matched with a response message. +However, the protocol itself is a message-passing protocol with which +other (non-RPC) protocols can be implemented.  Sun currently uses, or +perhaps abuses, the RPC message protocol for the following two +(non-RPC) protocols:  batching (or pipelining) and broadcast RPC. +These two protocols are discussed but not defined below. +.NH 3 +\&Batching +.LP +Batching allows a client to send an arbitrarily large sequence of +call messages to a server; batching typically uses reliable byte +stream protocols (like TCP/IP) for its transport.  In the case of +batching, the client never waits for a reply from the server, and the +server does not send replies to batch requests.  A sequence of batch +calls is usually terminated by a legitimate RPC in order to flush the +pipeline (with positive acknowledgement). +.NH 3 +\&Broadcast RPC +.LP +In broadcast RPC-based protocols, the client sends a broadcast packet +to the network and waits for numerous replies.  Broadcast RPC uses +unreliable, packet-based protocols (like UDP/IP) as its transports. +Servers that support broadcast protocols only respond when the +request is successfully processed, and are silent in the face of +errors.  Broadcast RPC uses the Port Mapper RPC service to achieve +its semantics.  See the \fIPort Mapper Program Protocol\fP\, below, +for more information. +.KS +.NH 1 +\&The RPC Message Protocol +.LP +This section defines the RPC message protocol in the XDR data +description language.  The message is defined in a top-down style. +.ie t .DS +.el .DS L +.ft CW +enum msg_type { +	CALL  = 0, +	REPLY = 1 +}; + +.ft I +/* +* A reply to a call message can take on two forms: +* The message was either accepted or rejected. +*/ +.ft CW +enum reply_stat { +	MSG_ACCEPTED = 0, +	MSG_DENIED   = 1 +}; + +.ft I +/* +* Given that a call message was accepted,  the following is the +* status of an attempt to call a remote procedure. +*/ +.ft CW +enum accept_stat { +	SUCCESS       = 0, /* \fIRPC executed successfully       \fP*/ +	PROG_UNAVAIL  = 1, /* \fIremote hasn't exported program  \fP*/ +	PROG_MISMATCH = 2, /* \fIremote can't support version #  \fP*/ +	PROC_UNAVAIL  = 3, /* \fIprogram can't support procedure \fP*/ +	GARBAGE_ARGS  = 4  /* \fIprocedure can't decode params   \fP*/ +}; +.DE +.ie t .DS +.el .DS L +.ft I +/* +* Reasons why a call message was rejected: +*/ +.ft CW +enum reject_stat { +	RPC_MISMATCH = 0, /* \fIRPC version number != 2          \fP*/ +	AUTH_ERROR = 1    /* \fIremote can't authenticate caller \fP*/ +}; + +.ft I +/* +* Why authentication failed: +*/ +.ft CW +enum auth_stat { +	AUTH_BADCRED      = 1,  /* \fIbad credentials \fP*/ +	AUTH_REJECTEDCRED = 2,  /* \fIclient must begin new session \fP*/ +	AUTH_BADVERF      = 3,  /* \fIbad verifier \fP*/ +	AUTH_REJECTEDVERF = 4,  /* \fIverifier expired or replayed  \fP*/ +	AUTH_TOOWEAK      = 5   /* \fIrejected for security reasons \fP*/ +}; +.DE +.KE +.ie t .DS +.el .DS L +.ft I +/* +* The  RPC  message:  +* All   messages  start with   a transaction  identifier,  xid, +* followed  by a  two-armed  discriminated union.   The union's +* discriminant is a  msg_type which switches to  one of the two +* types   of the message.   The xid  of a \fIREPLY\fP  message always +* matches  that of the initiating \fICALL\fP   message.   NB: The xid +* field is only  used for clients  matching reply messages with +* call messages  or for servers detecting  retransmissions; the +* service side  cannot treat this id  as any type   of sequence +* number. +*/ +.ft CW +struct rpc_msg { +	unsigned int xid; +	union switch (msg_type mtype) { +		case CALL: +			call_body cbody; +		case REPLY:   +			reply_body rbody; +	} body; +}; +.DE +.ie t .DS +.el .DS L +.ft I +/* +* Body of an RPC request call:  +* In version 2 of the  RPC protocol specification, rpcvers must +* be equal to 2.  The  fields prog,  vers, and proc specify the +* remote program, its version number, and the  procedure within +* the remote program to be called.  After these  fields are two +* authentication  parameters: cred (authentication credentials) +* and verf  (authentication verifier).  The  two authentication +* parameters are   followed by  the  parameters  to  the remote +* procedure,  which  are specified  by  the  specific   program +* protocol. +*/ +.ft CW +struct call_body { +	unsigned int rpcvers;  /* \fImust be equal to two (2) \fP*/ +	unsigned int prog; +	unsigned int vers; +	unsigned int proc; +	opaque_auth cred; +	opaque_auth verf; +	/* \fIprocedure specific parameters start here \fP*/ +}; +.DE +.ie t .DS +.el .DS L +.ft I +/* +* Body of a reply to an RPC request: +* The call message was either accepted or rejected. +*/ +.ft CW +union reply_body switch (reply_stat stat) { +	case MSG_ACCEPTED:   +		accepted_reply areply; +	case MSG_DENIED:   +		rejected_reply rreply; +} reply; +.DE +.ie t .DS +.el .DS L +.ft I +/* +* Reply to   an RPC request  that  was accepted  by the server: +* there could be an error even though the request was accepted. +* The first field is an authentication verifier that the server +* generates in order to  validate itself  to the caller.  It is +* followed by    a  union whose     discriminant  is   an  enum +* accept_stat.  The  \fISUCCESS\fP  arm of    the union  is  protocol +* specific.  The \fIPROG_UNAVAIL\fP, \fIPROC_UNAVAIL\fP, and \fIGARBAGE_ARGP\fP +* arms of the union are void.   The \fIPROG_MISMATCH\fP arm specifies +* the lowest and highest version numbers of the  remote program +* supported by the server. +*/ +.ft CW +struct accepted_reply { +	opaque_auth verf; +	union switch (accept_stat stat) { +		case SUCCESS: +			opaque results[0]; +			/* \fIprocedure-specific results start here\fP */ +		case PROG_MISMATCH: +			struct { +				unsigned int low; +				unsigned int high; +			} mismatch_info; +		default: +.ft I +			/* +			* Void.  Cases include \fIPROG_UNAVAIL, PROC_UNAVAIL\fP, +			* and \fIGARBAGE_ARGS\fP. +			*/ +.ft CW +			void; +	} reply_data; +}; +.DE +.ie t .DS +.el .DS L +.ft I +/* +* Reply to an RPC request that was rejected by the server:  +* The request  can   be rejected for   two reasons:  either the +* server   is not  running a   compatible  version  of the  RPC +* protocol    (\fIRPC_MISMATCH\fP), or    the  server   refuses    to +* authenticate the  caller  (\fIAUTH_ERROR\fP).  In  case of  an  RPC +* version mismatch,  the server returns the  lowest and highest +* supported    RPC  version    numbers.  In   case   of refused +* authentication, failure status is returned. +*/ +.ft CW +union rejected_reply switch (reject_stat stat) { +	case RPC_MISMATCH: +		struct { +			unsigned int low; +			unsigned int high; +		} mismatch_info; +	case AUTH_ERROR:  +		auth_stat stat; +}; +.DE +.NH 1 +\&Authentication Protocols +.LP +As previously stated, authentication parameters are opaque, but +open-ended to the rest of the RPC protocol.  This section defines +some "flavors" of authentication implemented at (and supported by) +Sun.  Other sites are free to invent new authentication types, with +the same rules of flavor number assignment as there is for program +number assignment. +.NH 2 +\&Null Authentication +.LP +Often calls must be made where the caller does not know who he is or +the server does not care who the caller is.  In this case, the flavor +value (the discriminant of the \fIopaque_auth\fP's union) of the RPC +message's credentials, verifier, and response verifier is +.I AUTH_NULL . +The  bytes of the opaque_auth's body  are undefined. +It is recommended that the opaque length be zero. +.NH 2 +\&UNIX Authentication +.LP +The caller of a remote procedure may wish to identify himself as he +is identified on a UNIX system.  The  value of the credential's +discriminant of an RPC call  message is   +.I AUTH_UNIX . +The bytes of +the credential's opaque body encode the following structure: +.DS +.ft CW +struct auth_unix { +	unsigned int stamp; +	string machinename<255>; +	unsigned int uid; +	unsigned int gid; +	unsigned int gids<10>; +}; +.DE +The  +.I stamp  +is an  arbitrary    ID which the  caller machine   may +generate.  The  +.I machinename  +is the  name of the  caller's machine (like  "krypton").  The  +.I uid  +is  the caller's effective user  ID.  The   +.I gid  +is  the caller's effective  group  ID.  The  +.I gids  +is  a +counted array of groups which contain the caller as  a member.  The +verifier accompanying the  credentials  should  be  of   +.I AUTH_NULL +(defined above). +.LP +The value of the discriminant of  the response verifier received in +the  reply  message  from  the    server  may   be    +.I AUTH_NULL  +or +.I AUTH_SHORT . +In  the  case  of  +.I AUTH_SHORT , +the bytes of the response verifier's string encode an opaque +structure.  This new opaque structure may now be passed to the server +instead of the original +.I AUTH_UNIX +flavor credentials.  The server keeps a cache which maps shorthand +opaque structures (passed back by way of an +.I AUTH_SHORT +style response verifier) to the original credentials of the caller. +The caller can save network bandwidth and server cpu cycles by using +the new credentials. +.LP +The server may flush the shorthand opaque structure at any time.  If +this happens, the remote procedure call message will be rejected due +to an authentication error.  The reason for the failure will be +.I AUTH_REJECTEDCRED . +At this point, the caller may wish to try the original +.I AUTH_UNIX +style of credentials. +.KS +.NH 2 +\&DES Authentication +.LP +UNIX authentication suffers from two major problems: +.IP  1. +The naming is too UNIX-system oriented. +.IP  2. +There is no verifier, so credentials can easily be faked. +.LP +DES authentication attempts to fix these two problems. +.KE +.NH 3 +\&Naming +.LP +The first problem is handled by addressing the caller by a simple +string of characters instead of by an operating system specific +integer.  This string of characters is known as the "netname" or +network name of the caller.  The server is not allowed to interpret +the contents of the caller's name in any other way except to +identify the caller.  Thus, netnames should be unique for every +caller in the internet. +.LP +It is up to each operating system's implementation of DES +authentication to generate netnames for its users that insure this +uniqueness when they call upon remote servers.  Operating systems +already know how to distinguish users local to their systems.  It is +usually a simple matter to extend this mechanism to the network. +For example, a UNIX user at Sun with a user ID of 515 might be +assigned the following netname: "unix.515@sun.com".  This netname +contains three items that serve to insure it is unique.  Going +backwards, there is only one naming domain called "sun.com" in the +internet.  Within this domain, there is only one UNIX user with +user ID 515.  However, there may be another user on another +operating system, for example VMS, within the same naming domain +that, by coincidence, happens to have the same user ID.  To insure +that these two users can be distinguished we add the operating +system name.  So one user is "unix.515@sun.com" and the other is +"vms.515@sun.com". +.LP +The first field is actually a naming method rather than an +operating system name.  It just happens that today there is almost +a one-to-one correspondence between naming methods and operating +systems.  If the world could agree on a naming standard, the first +field could be the name of that standard, instead of an operating +system name. +.LP +.NH 3 +\&DES Authentication Verifiers +.LP +Unlike UNIX authentication, DES authentication does have a verifier +so the server can validate the client's credential (and +vice-versa).  The contents of this verifier is primarily an +encrypted timestamp.  The server can decrypt this timestamp, and if +it is close to what the real time is, then the client must have +encrypted it correctly.  The only way the client could encrypt it +correctly is to know the "conversation key" of the RPC session.  And +if the client knows the conversation key, then it must be the real +client. +.LP +The conversation key is a DES [5] key which the client generates +and notifies the server of in its first RPC call.  The conversation +key is encrypted using a public key scheme in this first +transaction.  The particular public key scheme used in DES +authentication is Diffie-Hellman [3] with 192-bit keys.  The +details of this encryption method are described later. +.LP +The client and the server need the same notion of the current time +in order for all of this to work.  If network time synchronization +cannot be guaranteed, then client can synchronize with the server +before beginning the conversation, perhaps by consulting the +Internet Time Server (TIME[4]). +.LP +The way a server determines if a client timestamp is valid is +somewhat complicated.  For any other transaction but the first, the +server just checks for two things: +.IP  1. +the timestamp is greater than the one previously seen from the +same client. +.IP  2. +the timestamp has not expired. +.LP +A timestamp is expired if the server's time is later than the sum +of the client's timestamp plus what is known as the client's +"window".  The "window" is a number the client passes (encrypted) +to the server in its first transaction.  You can think of it as a +lifetime for the credential. +.LP +This explains everything but the first transaction.  In the first +transaction, the server checks only that the timestamp has not +expired.  If this was all that was done though, then it would be +quite easy for the client to send random data in place of the +timestamp with a fairly good chance of succeeding.  As an added +check, the client sends an encrypted item in the first transaction +known as the "window verifier" which must be equal to the window +minus 1, or the server will reject the credential. +.LP +The client too must check the verifier returned from the server to +be sure it is legitimate.  The server sends back to the client the +encrypted timestamp it received from the client, minus one second. +If the client gets anything different than this, it will reject it. +.LP +.NH 3 +\&Nicknames and Clock Synchronization +.LP +After the first transaction, the server's DES authentication +subsystem returns in its verifier to the client an integer +"nickname" which the client may use in its further transactions +instead of passing its netname, encrypted DES key and window every +time.  The nickname is most likely an index into a table on the +server which stores for each client its netname, decrypted DES key +and window. +.LP +Though they originally were synchronized, the client's and server's +clocks can get out of sync again.  When this happens the client RPC +subsystem most likely will get back +.I RPC_AUTHERROR  +at which point it should resynchronize. +.LP +A client may still get the +.I RPC_AUTHERROR  +error even though it is +synchronized with the server.  The reason is that the server's +nickname table is a limited size, and it may flush entries whenever +it wants.  A client should resend its original credential in this +case and the server will give it a new nickname.  If a server +crashes, the entire nickname table gets flushed, and all clients +will have to resend their original credentials. +.KS +.NH 3 +\&DES Authentication Protocol (in XDR language) +.ie t .DS +.el .DS L +.ft I +/* +* There are two kinds of credentials: one in which the client uses +* its full network name, and one in which it uses its "nickname" +* (just an unsigned integer) given to it by the server.  The +* client must use its fullname in its first transaction with the +* server, in which the server will return to the client its +* nickname.  The client may use its nickname in all further +* transactions with the server.  There is no requirement to use the +* nickname, but it is wise to use it for performance reasons. +*/ +.ft CW +enum authdes_namekind { +	ADN_FULLNAME = 0, +	ADN_NICKNAME = 1 +}; + +.ft I +/* +* A 64-bit block of encrypted DES data +*/ +.ft CW +typedef opaque des_block[8]; + +.ft I +/* +* Maximum length of a network user's name +*/ +.ft CW +const MAXNETNAMELEN = 255; + +.ft I +/* +* A fullname contains the network name of the client, an encrypted +* conversation key and the window.  The window is actually a +* lifetime for the credential.  If the time indicated in the +* verifier timestamp plus the window has past, then the server +* should expire the request and not grant it.  To insure that +* requests are not replayed, the server should insist that +* timestamps are greater than the previous one seen, unless it is +* the first transaction.  In the first transaction, the server +* checks instead that the window verifier is one less than the +* window. +*/ +.ft CW +struct authdes_fullname { +string name<MAXNETNAMELEN>;  /* \fIname of client \f(CW*/ +des_block key;               /* \fIPK encrypted conversation key \f(CW*/ +unsigned int window;         /* \fIencrypted window \f(CW*/ +}; + +.ft I +/* +* A credential is either a fullname or a nickname +*/ +.ft CW +union authdes_cred switch (authdes_namekind adc_namekind) { +	case ADN_FULLNAME: +		authdes_fullname adc_fullname; +	case ADN_NICKNAME: +		unsigned int adc_nickname; +}; + +.ft I +/* +* A timestamp encodes the time since midnight, January 1, 1970. +*/ +.ft CW +struct timestamp { +	unsigned int seconds;    /* \fIseconds \fP*/ +	unsigned int useconds;   /* \fIand microseconds \fP*/ +}; + +.ft I +/* +* Verifier: client variety +* The window verifier is only used in the first transaction.  In +* conjunction with a fullname credential, these items are packed +* into the following structure before being encrypted: +* +* \f(CWstruct {\fP +*     \f(CWadv_timestamp;            \fP-- one DES block +*     \f(CWadc_fullname.window;      \fP-- one half DES block +*     \f(CWadv_winverf;              \fP-- one half DES block +* \f(CW}\fP +* This structure is encrypted using CBC mode encryption with an +* input vector of zero.  All other encryptions of timestamps use +* ECB mode encryption. +*/ +.ft CW +struct authdes_verf_clnt { +	timestamp adv_timestamp;    /* \fIencrypted timestamp       \fP*/ +	unsigned int adv_winverf;   /* \fIencrypted window verifier \fP*/ +}; + +.ft I +/* +* Verifier: server variety +* The server returns (encrypted) the same timestamp the client +* gave it minus one second.  It also tells the client its nickname +* to be used in future transactions (unencrypted). +*/ +.ft CW +struct authdes_verf_svr { +timestamp adv_timeverf;     /* \fIencrypted verifier      \fP*/ +unsigned int adv_nickname;  /* \fInew nickname for client \fP*/ +}; +.DE +.KE +.NH 3 +\&Diffie-Hellman Encryption +.LP +In this scheme, there are two constants, +.I BASE  +and +.I MODULUS . +The +particular values Sun has chosen for these for the DES +authentication protocol are: +.ie t .DS +.el .DS L +.ft CW +const BASE = 3; +const MODULUS =  +        "d4a0ba0250b6fd2ec626e7efd637df76c716e22d0944b88b"; /* \fIhex \fP*/ +.DE +.ft R +The way this scheme works is best explained by an example.  Suppose +there are two people "A" and "B" who want to send encrypted +messages to each other.  So, A and B both generate "secret" keys at +random which they do not reveal to anyone.  Let these keys be +represented as SK(A) and SK(B).  They also publish in a public +directory their "public" keys.  These keys are computed as follows: +.ie t .DS +.el .DS L +.ft CW +PK(A) = ( BASE ** SK(A) ) mod MODULUS +PK(B) = ( BASE ** SK(B) ) mod MODULUS +.DE +.ft R +The "**" notation is used here to represent exponentiation.  Now, +both A and B can arrive at the "common" key between them, +represented here as CK(A, B), without revealing their secret keys. +.LP +A computes: +.ie t .DS +.el .DS L +.ft CW +CK(A, B) = ( PK(B) ** SK(A)) mod MODULUS +.DE +.ft R +while B computes: +.ie t .DS +.el .DS L +.ft CW +CK(A, B) = ( PK(A) ** SK(B)) mod MODULUS +.DE +.ft R +These two can be shown to be equivalent: +.ie t .DS +.el .DS L +.ft CW +(PK(B) ** SK(A)) mod MODULUS = (PK(A) ** SK(B)) mod MODULUS +.DE +.ft R +We drop the "mod MODULUS" parts and assume modulo arithmetic to +simplify things: +.ie t .DS +.el .DS L +.ft CW +PK(B) ** SK(A) = PK(A) ** SK(B) +.DE +.ft R +Then, replace PK(B) by what B computed earlier and likewise for +PK(A). +.ie t .DS +.el .DS L +.ft CW +((BASE ** SK(B)) ** SK(A) = (BASE ** SK(A)) ** SK(B) +.DE +.ft R +which leads to: +.ie t .DS +.el .DS L +.ft CW +BASE ** (SK(A) * SK(B)) = BASE ** (SK(A) * SK(B)) +.DE +.ft R +This common key CK(A, B) is not used to encrypt the timestamps used +in the protocol.  Rather, it is used only to encrypt a conversation +key which is then used to encrypt the timestamps.  The reason for +doing this is to use the common key as little as possible, for fear +that it could be broken.  Breaking the conversation key is a far +less serious offense, since conversations are relatively +short-lived. +.LP +The conversation key is encrypted using 56-bit DES keys, yet the +common key is 192 bits.  To reduce the number of bits, 56 bits are +selected from the common key as follows.  The middle-most 8-bytes +are selected from the common key, and then parity is added to the +lower order bit of each byte, producing a 56-bit key with 8 bits of +parity. +.KS +.NH 1 +\&Record Marking Standard +.LP +When RPC messages are passed on top of a byte stream protocol (like +TCP/IP), it is necessary, or at least desirable, to delimit one +message from another in order to detect and possibly recover from +user protocol errors.  This is called record marking (RM).  Sun uses +this RM/TCP/IP transport for passing RPC messages on TCP streams. +One RPC message fits into one RM record. +.LP +A record is composed of one or more record fragments.  A record +fragment is a four-byte header followed by 0 to (2**31) - 1 bytes of +fragment data.  The bytes encode an unsigned binary number; as with +XDR integers, the byte order is from highest to lowest.  The number +encodes two values\(ema boolean which indicates whether the fragment +is the last fragment of the record (bit value 1 implies the fragment +is the last fragment) and a 31-bit unsigned binary value which is the +length in bytes of the fragment's data.  The boolean value is the +highest-order bit of the header; the length is the 31 low-order bits. +(Note that this record specification is NOT in XDR standard form!) +.KE +.KS +.NH 1 +\&The RPC Language +.LP +Just as there was a need to describe the XDR data-types in a formal +language, there is also need to describe the procedures that operate +on these XDR data-types in a formal language as well.  We use the RPC +Language for this purpose.  It is an extension to the XDR language. +The following example is used to describe the essence of the +language. +.NH 2 +\&An Example Service Described in the RPC Language +.LP +Here is an example of the specification of a simple ping program. +.ie t .DS +.el .DS L +.vs 11 +.ft I +/* +* Simple ping program +*/ +.ft CW +program PING_PROG { +	/* \fILatest and greatest version\fP */ +	version PING_VERS_PINGBACK { +	void  +	PINGPROC_NULL(void) = 0; + +.ft I +	/* +	* Ping the caller, return the round-trip time +	* (in microseconds). Returns -1 if the operation +	* timed out. +	*/ +.ft CW +	int +	PINGPROC_PINGBACK(void) = 1;         +} = 2;      + +.ft I +/* +* Original version +*/ +.ft CW +version PING_VERS_ORIG { +	void  +	PINGPROC_NULL(void) = 0; +	} = 1; +} = 1; + +const PING_VERS = 2;      /* \fIlatest version \fP*/ +.vs +.DE +.KE +.LP +The first version described is +.I PING_VERS_PINGBACK +with  two procedures,    +.I PINGPROC_NULL  +and  +.I PINGPROC_PINGBACK . +.I PINGPROC_NULL  +takes no arguments and returns no results, but it is useful for +computing round-trip times from the client to the server and back +again.  By convention, procedure 0 of any RPC protocol should have +the same semantics, and never require any kind of authentication. +The second procedure is used for the client to have the server do a +reverse ping operation back to the client, and it returns the amount +of time (in microseconds) that the operation used.  The next version, +.I PING_VERS_ORIG , +is the original version of the protocol +and it does not contain +.I PINGPROC_PINGBACK +procedure. It  is useful +for compatibility  with old client  programs,  and as  this program +matures it may be dropped from the protocol entirely. +.KS +.NH 2 +\&The RPC Language Specification +.LP +The  RPC language is identical to  the XDR language, except for the +added definition of a +.I program-def  +described below. +.DS +.ft CW +program-def: +	"program" identifier "{" +		version-def  +		version-def * +	"}" "=" constant ";" + +version-def: +	"version" identifier "{" +		procedure-def +		procedure-def * +	"}" "=" constant ";" + +procedure-def: +	type-specifier identifier "(" type-specifier ")" +	"=" constant ";" +.DE +.KE +.NH 2 +\&Syntax Notes +.IP  1. +The following keywords  are  added  and   cannot  be used   as +identifiers: "program" and "version"; +.IP  2. +A version name cannot occur more than once within the  scope of +a program definition. Nor can a version number occur more than once +within the scope of a program definition. +.IP  3. +A procedure name cannot occur  more than once within  the scope +of a version definition. Nor can a procedure number occur more than +once within the scope of version definition. +.IP  4. +Program identifiers are in the same name space as  constant and +type identifiers. +.IP  5. +Only unsigned constants can  be assigned to programs, versions +and procedures. +.NH 1 +\&Port Mapper Program Protocol +.LP +The port mapper program maps RPC program and version numbers to +transport-specific port numbers.  This program makes dynamic binding +of remote programs possible. +.LP +This is desirable because the range of reserved port numbers is very +small and the number of potential remote programs is very large.  By +running only the port mapper on a reserved port, the port numbers of +other remote programs can be ascertained by querying the port mapper. +.LP +The port mapper also aids in broadcast RPC.  A given RPC program will +usually have different port number bindings on different machines, so +there is no way to directly broadcast to all of these programs.  The +port mapper, however, does have a fixed port number.  So, to +broadcast to a given program, the client actually sends its message +to the port mapper located at the broadcast address.  Each port +mapper that picks up the broadcast then calls the local service +specified by the client.  When the port mapper gets the reply from +the local service, it sends the reply on back to the client. +.KS +.NH 2 +\&Port Mapper Protocol Specification (in RPC Language) +.ie t .DS +.el .DS L +.ft CW +.vs 11 +const PMAP_PORT = 111;      /* \fIportmapper port number \fP*/ + +.ft I +/* +* A mapping of (program, version, protocol) to port number +*/ +.ft CW +struct mapping { +	unsigned int prog; +	unsigned int vers; +	unsigned int prot; +	unsigned int port; +}; + +.ft I +/*  +* Supported values for the "prot" field +*/ +.ft CW +const IPPROTO_TCP = 6;      /* \fIprotocol number for TCP/IP \fP*/ +const IPPROTO_UDP = 17;     /* \fIprotocol number for UDP/IP \fP*/ + +.ft I +/* +* A list of mappings +*/ +.ft CW +struct *pmaplist { +	mapping map; +	pmaplist next; +}; +.vs +.DE +.ie t .DS +.el .DS L +.vs 11 +.ft I +/* +* Arguments to callit +*/ +.ft CW +struct call_args { +	unsigned int prog; +	unsigned int vers; +	unsigned int proc; +	opaque args<>; +};   + +.ft I +/* +* Results of callit +*/ +.ft CW +struct call_result { +	unsigned int port; +	opaque res<>; +}; +.vs +.DE +.KE +.ie t .DS +.el .DS L +.vs 11 +.ft I +/* +* Port mapper procedures +*/ +.ft CW +program PMAP_PROG { +	version PMAP_VERS { +		void  +		PMAPPROC_NULL(void)         = 0; + +		bool +		PMAPPROC_SET(mapping)       = 1; + +		bool +		PMAPPROC_UNSET(mapping)     = 2; + +		unsigned int +		PMAPPROC_GETPORT(mapping)   = 3; + +		pmaplist +		PMAPPROC_DUMP(void)         = 4; + +		call_result +		PMAPPROC_CALLIT(call_args)  = 5; +	} = 2; +} = 100000; +.vs +.DE +.NH 2 +\&Port Mapper Operation +.LP +The portmapper program currently supports two protocols (UDP/IP and +TCP/IP).  The portmapper is contacted by talking to it on assigned +port number 111 (SUNRPC [8]) on either of these protocols.  The +following is a description of each of the portmapper procedures: +.IP \fBPMAPPROC_NULL:\fP +This procedure does no work.  By convention, procedure zero of any +protocol takes no parameters and returns no results. +.IP \fBPMAPPROC_SET:\fP +When a program first becomes available on a machine, it registers +itself with the port mapper program on the same machine.  The program +passes its program number "prog", version number "vers", transport +protocol number "prot", and the port "port" on which it awaits +service request.  The procedure returns a boolean response whose +value is +.I TRUE +if the procedure successfully established the mapping and  +.I FALSE  +otherwise.  The procedure refuses to establish +a mapping if one already exists for the tuple "(prog, vers, prot)". +.IP \fBPMAPPROC_UNSET:\fP +When a program becomes unavailable, it should unregister itself with +the port mapper program on the same machine.  The parameters and +results have meanings identical to those of +.I PMAPPROC_SET . +The protocol and port number fields of the argument are ignored. +.IP \fBPMAPPROC_GETPORT:\fP +Given a program number "prog", version number "vers", and transport +protocol number "prot", this procedure returns the port number on +which the program is awaiting call requests.  A port value of zeros +means the program has not been registered.  The "port" field of the +argument is ignored. +.IP \fBPMAPPROC_DUMP:\fP +This procedure enumerates all entries in the port mapper's database. +The procedure takes no parameters and returns a list of program, +version, protocol, and port values. +.IP \fBPMAPPROC_CALLIT:\fP +This procedure allows a caller to call another remote procedure on +the same machine without knowing the remote procedure's port number. +It is intended for supporting broadcasts to arbitrary remote programs +via the well-known port mapper's port.  The parameters "prog", +"vers", "proc", and the bytes of "args" are the program number, +version number, procedure number, and parameters of the remote +procedure. +.LP +.B Note: +.RS +.IP  1. +This procedure only sends a response if the procedure was +successfully executed and is silent (no response) otherwise. +.IP  2. +The port mapper communicates with the remote program using UDP/IP +only. +.RE +.LP +The procedure returns the remote program's port number, and the bytes +of results are the results of the remote procedure. +.bp +.NH 1 +\&References +.LP +[1]  Birrell, Andrew D. & Nelson, Bruce Jay; "Implementing Remote +Procedure Calls"; XEROX CSL-83-7, October 1983. +.LP +[2]  Cheriton, D.; "VMTP:  Versatile Message Transaction Protocol", +Preliminary Version 0.3; Stanford University, January 1987. +.LP +[3]  Diffie & Hellman; "New Directions in Cryptography"; IEEE +Transactions on Information Theory IT-22, November 1976. +.LP +[4]  Harrenstien, K.; "Time Server", RFC 738; Information Sciences +Institute, October 1977. +.LP +[5]  National Bureau of Standards; "Data Encryption Standard"; Federal +Information Processing Standards Publication 46, January 1977. +.LP +[6]  Postel, J.; "Transmission Control Protocol - DARPA Internet +Program Protocol Specification", RFC 793; Information Sciences +Institute, September 1981. +.LP +[7]  Postel, J.; "User Datagram Protocol", RFC 768; Information Sciences +Institute, August 1980. +.LP +[8]  Reynolds, J.  & Postel, J.; "Assigned Numbers", RFC 923; Information +Sciences Institute, October 1984. diff --git a/lib/librpc/doc/rpcgen.ms b/lib/librpc/doc/rpcgen.ms new file mode 100644 index 000000000000..b4e50e5d6f04 --- /dev/null +++ b/lib/librpc/doc/rpcgen.ms @@ -0,0 +1,1299 @@ +.\" +.\" Must use  --  tbl -- for this one +.\" +.\" @(#)rpcgen.ms	2.2 88/08/04 4.0 RPCSRC +.de BT +.if \\n%=1 .tl ''- % -'' +.. +.ND +.\" prevent excess underlining in nroff +.if n .fp 2 R +.OH '\fBrpcgen\fP Programming Guide''Page %' +.EH 'Page %''\fBrpcgen\fP Programming Guide' +.if \\n%=1 .bp +.SH +\&\fBrpcgen\fP Programming Guide +.NH 0 +\&The \fBrpcgen\fP Protocol Compiler +.IX rpcgen "" \fIrpcgen\fP "" PAGE MAJOR +.LP +.IX RPC "" "" \fIrpcgen\fP +The details of programming applications to use Remote Procedure Calls  +can be overwhelming.  Perhaps most daunting is the writing of the XDR  +routines necessary to convert procedure arguments and results into  +their network format and vice-versa.   +.LP +Fortunately,  +.I rpcgen(1)  +exists to help programmers write RPC applications simply and directly. +.I rpcgen  +does most of the dirty work, allowing programmers to debug  +the  main  features of their application, instead of requiring them to +spend most of their time debugging their network interface code. +.LP +.I rpcgen  +is a  compiler.  It accepts a remote program interface definition written +in a language, called RPC Language, which is similar to C.  It produces a C +language output which includes stub versions of the client routines, a +server skeleton, XDR filter routines for both parameters and results, and a +header file that contains common definitions. The client stubs interface +with the RPC library and effectively hide the network from their callers. +The server stub similarly hides the network from the server procedures that +are to be invoked by remote clients. +.I rpcgen 's +output files can be compiled and linked in the usual way.  The developer +writes server procedures\(emin any language that observes Sun calling +conventions\(emand links them with the server skeleton produced by +.I rpcgen  +to get an executable server program.  To use a remote program, a programmer +writes an ordinary main program that makes local procedure calls to the  +client stubs produced by +.I rpcgen . +Linking this program with  +.I rpcgen 's +stubs creates an executable program.  (At present the main program must be  +written in C). +.I rpcgen  +options can be used to suppress stub generation and to specify the transport +to be used by the server stub. +.LP +Like all compilers,  +.I rpcgen  +reduces development time +that would otherwise be spent coding and debugging low-level routines. +All compilers, including  +.I rpcgen , +do this at a small cost in efficiency +and flexibility.  However,   many compilers allow  escape  hatches for +programmers to  mix low-level code with  high-level code.  +.I rpcgen  +is no exception.  In speed-critical applications, hand-written routines  +can be linked with the  +.I rpcgen  +output without any difficulty.  Also, one may proceed by using +.I rpcgen  +output as a starting point, and then rewriting it as necessary. +(If you need a discussion of RPC programming without +.I rpcgen , +see the +.I "Remote Procedure Call Programming Guide)\. +.NH 1 +\&Converting Local Procedures into Remote Procedures +.IX rpcgen "local procedures" \fIrpcgen\fP +.IX rpcgen "remote procedures" \fIrpcgen\fP +.LP +Assume an application that runs on a single machine, one which we want  +to convert to run over the network.  Here we will demonstrate such a  +conversion by way of a simple example\(ema program that prints a  +message to the console: +.ie t .DS +.el .DS L +.ft I +/* + * printmsg.c: print a message on the console + */ +.ft CW +#include <stdio.h> + +main(argc, argv) +	int argc; +	char *argv[]; +{ +	char *message; + +	if (argc < 2) { +		fprintf(stderr, "usage: %s <message>\en", argv[0]); +		exit(1); +	} +	message = argv[1]; + +	if (!printmessage(message)) { +		fprintf(stderr, "%s: couldn't print your message\en", +			argv[0]); +		exit(1); +	}  +	printf("Message Delivered!\en"); +	exit(0); +} +.ft I +/* + * Print a message to the console. + * Return a boolean indicating whether the message was actually printed. + */ +.ft CW +printmessage(msg) +	char *msg; +{ +	FILE *f; + +	f = fopen("/dev/console", "w"); +	if (f == NULL) { +		return (0); +	} +	fprintf(f, "%s\en", msg); +	fclose(f); +	return(1); +} +.DE +.LP +And then, of course: +.ie t .DS +.el .DS L +.ft CW +example%  \fBcc printmsg.c -o printmsg\fP +example%  \fBprintmsg "Hello, there."\fP +Message delivered! +example% +.DE +.LP +If   +.I printmessage()  +was turned into  a remote procedure, +then it could be  called from anywhere in   the network.   +Ideally,  one would just  like to stick   a  keyword like   +.I remote  +in  front  of a +procedure to turn it into a  remote procedure.  Unfortunately, +we  have to live  within the  constraints of  the   C language, since  +it existed   long before  RPC did.  But   even without language  +support, it's not very difficult to make a procedure remote. +.LP +In  general, it's necessary to figure  out  what the types are for +all procedure inputs and outputs.  In  this case,   we  have a  +procedure +.I printmessage()  +which takes a  string as input, and returns  an integer +as output.  Knowing  this, we can write a  protocol specification in RPC +language that  describes the remote  version of  +.I printmessage (). +Here it is: +.ie t .DS +.el .DS L +.ft I +/* + * msg.x: Remote message printing protocol + */ +.ft CW + +program MESSAGEPROG { +	version MESSAGEVERS { +		int PRINTMESSAGE(string) = 1; +	} = 1; +} = 99; +.DE +.LP +Remote procedures are part of remote programs, so we actually declared +an  entire  remote program  here  which contains  the single procedure +.I PRINTMESSAGE . +This procedure was declared to be  in version  1 of the +remote program.  No null procedure (procedure 0) is necessary because +.I rpcgen  +generates it automatically. +.LP +Notice that everything is declared with all capital  letters.  This is +not required, but is a good convention to follow. +.LP +Notice also that the argument type is \*Qstring\*U and not \*Qchar *\*U.  This +is because a \*Qchar *\*U in C is ambiguous.  Programmers usually intend it +to mean  a null-terminated string   of characters, but  it  could also +represent a pointer to a single character or a  pointer to an array of +characters.  In  RPC language,  a  null-terminated  string is  +unambiguously called a \*Qstring\*U. +.LP +There are  just two more things to  write.  First, there is the remote +procedure itself.  Here's the definition of a remote procedure +to implement the +.I PRINTMESSAGE +procedure we declared above: +.ie t .DS +.el .DS L +.vs 11 +.ft I +/* + * msg_proc.c: implementation of the remote procedure "printmessage" + */ +.ft CW + +#include <stdio.h> +#include <rpc/rpc.h>    /* \fIalways needed\fP  */ +#include "msg.h"        /* \fIneed this too: msg.h will be generated by rpcgen\fP */ + +.ft I +/* + * Remote verson of "printmessage" + */ +.ft CW +int * +printmessage_1(msg) +	char **msg; +{ +	static int result;  /* \fImust be static!\fP */ +	FILE *f; + +	f = fopen("/dev/console", "w"); +	if (f == NULL) { +		result = 0; +		return (&result); +	} +	fprintf(f, "%s\en", *msg); +	fclose(f); +	result = 1; +	return (&result); +} +.vs +.DE +.LP +Notice here that the declaration of the remote procedure +.I printmessage_1()  +differs from that of the local procedure +.I printmessage()  +in three ways: +.IP  1. +It takes a pointer to a string instead of a string itself.  This +is true of all  remote procedures:  they always take pointers to  their +arguments rather than the arguments themselves. +.IP  2. +It returns a pointer to an  integer instead of  an integer itself. This is +also generally true of remote procedures: they always return a pointer +to their results. +.IP  3. +It has an \*Q_1\*U appended to its name.  In general, all remote +procedures called by  +.I rpcgen  +are named by  the following rule: the name in the program  definition   +(here  +.I PRINTMESSAGE ) +is converted   to all +lower-case letters, an underbar (\*Q_\*U) is appended to it, and +finally the version number (here 1) is appended. +.LP +The last thing to do is declare the main client program that will call +the remote procedure. Here it is: +.ie t .DS +.el .DS L +.ft I +/* + * rprintmsg.c: remote version of "printmsg.c" + */ +.ft CW +#include <stdio.h> +#include <rpc/rpc.h>     /* \fIalways needed\fP  */ +#include "msg.h"         /* \fIneed this too: msg.h will be generated by rpcgen\fP */ + +main(argc, argv) +	int argc; +	char *argv[]; +{ +	CLIENT *cl; +	int *result; +	char *server; +	char *message; + +	if (argc < 3) { +		fprintf(stderr, "usage: %s host message\en", argv[0]); +		exit(1); +	} + +.ft I +	/* +	 * Save values of command line arguments  +	 */ +.ft CW +	server = argv[1]; +	message = argv[2]; + +.ft I +	/* +	 * Create client "handle" used for calling \fIMESSAGEPROG\fP on the +	 * server designated on the command line. We tell the RPC package +	 * to use the "tcp" protocol when contacting the server. +	 */ +.ft CW +	cl = clnt_create(server, MESSAGEPROG, MESSAGEVERS, "tcp"); +	if (cl == NULL) { +.ft I +		/* +		 * Couldn't establish connection with server. +		 * Print error message and die. +		 */ +.ft CW +		clnt_pcreateerror(server); +		exit(1); +	} + +.ft I +	/* +	 * Call the remote procedure "printmessage" on the server +	 */ +.ft CW +	result = printmessage_1(&message, cl); +	if (result == NULL) { +.ft I +		/* +		 * An error occurred while calling the server.  +	 	 * Print error message and die. +		 */ +.ft CW +		clnt_perror(cl, server); +		exit(1); +	} + +.ft I +	/* +	 * Okay, we successfully called the remote procedure. +	 */ +.ft CW +	if (*result == 0) { +.ft I +		/* +		 * Server was unable to print our message.  +		 * Print error message and die. +		 */ +.ft CW +		fprintf(stderr, "%s: %s couldn't print your message\en",  +			argv[0], server);	 +		exit(1); +	}  + +.ft I +	/* +	 * The message got printed on the server's console +	 */ +.ft CW +	printf("Message delivered to %s!\en", server); +} +.DE +There are two things to note here: +.IP  1. +.IX "client handle, used by rpcgen" "" "client handle, used by \fIrpcgen\fP" +First a client \*Qhandle\*U is created using the RPC library routine +.I clnt_create (). +This client handle will be passed  to the stub routines +which call the remote procedure. +.IP  2. +The remote procedure   +.I printmessage_1()  +is called exactly  the same way as it is  declared in  +.I msg_proc.c  +except for the inserted client handle as the first argument. +.LP +Here's how to put all of the pieces together: +.ie t .DS +.el .DS L +.ft CW +example%  \fBrpcgen msg.x\fP +example%  \fBcc rprintmsg.c msg_clnt.c -o rprintmsg\fP +example%  \fBcc msg_proc.c msg_svc.c -o msg_server\fP +.DE +Two programs were compiled here: the client program  +.I rprintmsg  +and the server  program  +.I msg_server . +Before doing this  though,   +.I rpcgen  +was used to fill in the missing pieces.   +.LP +Here is what  +.I rpcgen  +did with the input file  +.I msg.x : +.IP  1. +It created a header file called  +.I msg.h  +that contained +.I #define 's +for +.I MESSAGEPROG , +.I MESSAGEVERS  +and     +.I PRINTMESSAGE  +for use in  the  other modules. +.IP  2. +It created client \*Qstub\*U routines in the +.I msg_clnt.c  +file.   In this case there is only one, the  +.I printmessage_1()  +that was referred to from the +.I printmsg  +client program.  The name  of the output file for +client stub routines is always formed in this way:  if the name of the +input file is   +.I FOO.x , +the   client  stubs   output file is    called +.I FOO_clnt.c . +.IP  3. +It created  the  server   program which calls    +.I printmessage_1()  +in +.I msg_proc.c . +This server program is named   +.I msg_svc.c . +The rule for naming the server output file is similar  to the  +previous one:  for an input  file   called   +.I FOO.x , +the   output   server   file is  named +.I FOO_svc.c . +.LP +Now we're ready to have some fun.  First, copy the server to a +remote machine and run it.  For this  example,  the +machine is called \*Qmoon\*U.  Server processes are run in the +background, because they never exit. +.ie t .DS +.el .DS L +.ft CW +moon% \fBmsg_server &\fP	        +.DE +Then on our local machine (\*Qsun\*U) we can print a message on \*Qmoon\*Us +console. +.ie t .DS +.el .DS L +.ft CW +sun% \fBprintmsg moon "Hello, moon."\fP +.DE +The message will get printed to \*Qmoon\*Us console.  You can print a +message on anybody's console (including your own) with this program if +you are able to copy the server to their machine and run it. +.NH 1 +\&Generating XDR Routines +.IX RPC "generating XDR routines" +.LP +The previous example  only demonstrated  the  automatic generation of +client  and server RPC  code.  +.I rpcgen  +may also  be used to generate XDR routines, that  is,  the routines +necessary to  convert   local  data +structures into network format and vice-versa.  This example presents +a complete RPC service\(ema remote directory listing service, which uses +.I rpcgen +not  only  to generate stub routines, but also to  generate  the XDR +routines.  Here is the protocol description file: +.ie t .DS +.el .DS L +.ft I +/* + * dir.x: Remote directory listing protocol + */ +.ft CW +const MAXNAMELEN = 255;		/* \fImaximum length of a directory entry\fP */ + +typedef string nametype<MAXNAMELEN>;	/* \fIa directory entry\fP */ + +typedef struct namenode *namelist;		/* \fIa link in the listing\fP */ + +.ft I +/* + * A node in the directory listing + */ +.ft CW +struct namenode { +	nametype name;		/* \fIname of directory entry\fP */ +	namelist next;		/* \fInext entry\fP */ +}; + +.ft I +/* + * The result of a READDIR operation. + */ +.ft CW +union readdir_res switch (int errno) { +case 0: +	namelist list;	/* \fIno error: return directory listing\fP */ +default: +	void;		/* \fIerror occurred: nothing else to return\fP */ +}; + +.ft I +/* + * The directory program definition + */ +.ft CW +program DIRPROG { +	version DIRVERS { +		readdir_res +		READDIR(nametype) = 1; +	} = 1; +} = 76; +.DE +.SH +Note: +.I +Types (like +.I readdir_res  +in the example above) can be defined using +the \*Qstruct\*U, \*Qunion\*U and \*Qenum\*U keywords, but those keywords +should not be used in subsequent declarations of variables of those types. +For example, if you define a union \*Qfoo\*U, you should declare using +only \*Qfoo\*U and not \*Qunion foo\*U.  In fact, +.I rpcgen  +compiles +RPC unions into C structures and it is an error to declare them using the +\*Qunion\*U keyword. +.LP +Running  +.I rpcgen  +on  +.I dir.x  +creates four output files.  Three are the same as before: header file, +client stub routines and server skeleton.  The fourth are the XDR routines +necessary for converting the data types we declared into XDR format and +vice-versa.  These are output in the file +.I dir_xdr.c . +.LP +Here is the implementation of the +.I READDIR  +procedure. +.ie t .DS +.el .DS L +.vs 11 +.ft I +/* + * dir_proc.c: remote readdir implementation + */ +.ft CW +#include <rpc/rpc.h> +#include <sys/dir.h> +#include "dir.h" + +extern int errno; +extern char *malloc(); +extern char *strdup(); + +readdir_res * +readdir_1(dirname) +	nametype *dirname; +{ +	DIR *dirp; +	struct direct *d; +	namelist nl; +	namelist *nlp; +	static readdir_res res; /* \fImust be static\fP! */ + +.ft I +	/* +	 * Open directory +	 */ +.ft CW +	dirp = opendir(*dirname); +	if (dirp == NULL) { +		res.errno = errno; +		return (&res); +	} + +.ft I +	/* +	 * Free previous result +	 */ +.ft CW +	xdr_free(xdr_readdir_res, &res); + +.ft I +	/* +	 * Collect directory entries. +	 * Memory allocated here will be freed by \fIxdr_free\fP +	 * next time \fIreaddir_1\fP is called +	 */ +.ft CW +	nlp = &res.readdir_res_u.list; +	while (d = readdir(dirp)) { +		nl = *nlp = (namenode *) malloc(sizeof(namenode)); +		nl->name = strdup(d->d_name); +		nlp = &nl->next; +	} +	*nlp = NULL; + +.ft I +	/* +	 * Return the result +	 */ +.ft CW +	res.errno = 0; +	closedir(dirp); +	return (&res); +} +.vs +.DE +Finally, there is the client side program to call the server: +.ie t .DS +.el .DS L +.ft I +/* + * rls.c: Remote directory listing client + */ +.ft CW +#include <stdio.h> +#include <rpc/rpc.h>	/* \fIalways need this\fP */ +#include "dir.h"		/* \fIwill be generated by rpcgen\fI */ + +extern int errno; + +main(argc, argv) +	int argc; +	char *argv[]; +{ +	CLIENT *cl; +	char *server; +	char *dir; +	readdir_res *result; +	namelist nl; + + +	if (argc != 3) { +		fprintf(stderr, "usage: %s host directory\en",  +		  argv[0]); +		exit(1); +	} + +.ft I +	/* +	 * Remember what our command line arguments refer to +	 */ +.ft CW +	server = argv[1]; +	dir = argv[2]; + +.ft I +	/* +	 * Create client "handle" used for calling \fIMESSAGEPROG\fP on the +	 * server designated on the command line. We tell the RPC package +	 * to use the "tcp" protocol when contacting the server. +	 */ +.ft CW +	cl = clnt_create(server, DIRPROG, DIRVERS, "tcp"); +	if (cl == NULL) { +.ft I +		/* +		 * Couldn't establish connection with server. +		 * Print error message and die. +		 */ +.ft CW +		clnt_pcreateerror(server); +		exit(1); +	} + +.ft I +	/* +	 * Call the remote procedure \fIreaddir\fP on the server +	 */ +.ft CW +	result = readdir_1(&dir, cl); +	if (result == NULL) { +.ft I +		/* +		 * An error occurred while calling the server.  +	 	 * Print error message and die. +		 */ +.ft CW +		clnt_perror(cl, server); +		exit(1); +	} + +.ft I +	/* +	 * Okay, we successfully called the remote procedure. +	 */ +.ft CW +	if (result->errno != 0) { +.ft I +		/* +		 * A remote system error occurred. +		 * Print error message and die. +		 */ +.ft CW +		errno = result->errno; +		perror(dir); +		exit(1); +	} + +.ft I +	/* +	 * Successfully got a directory listing. +	 * Print it out. +	 */ +.ft CW +	for (nl = result->readdir_res_u.list; nl != NULL;  +	  nl = nl->next) { +		printf("%s\en", nl->name); +	} +	exit(0); +} +.DE +Compile everything, and run. +.DS +.ft CW +sun%  \fBrpcgen dir.x\fP +sun%  \fBcc rls.c dir_clnt.c dir_xdr.c -o rls\fP +sun%  \fBcc dir_svc.c dir_proc.c dir_xdr.c -o dir_svc\fP + +sun%  \fBdir_svc &\fP + +moon%  \fBrls sun /usr/pub\fP +\&. +\&.. +ascii +eqnchar +greek +kbd +marg8 +tabclr +tabs +tabs4 +moon% +.DE +.LP +.IX "debugging with rpcgen" "" "debugging with \fIrpcgen\fP" +A final note about  +.I rpcgen : +The client program and the server procedure can be tested together  +as a single program by simply linking them with each other rather  +than with the client and server stubs.  The procedure calls will be +executed as ordinary local procedure calls and the program can be  +debugged with a local debugger such as  +.I dbx . +When the program is working, the client program can be linked to  +the client stub produced by  +.I rpcgen  +and the server procedures can be linked to the server stub produced +by  +.I rpcgen . +.SH +.I NOTE : +\fIIf you do this, you may want to comment out calls to RPC library +routines, and have client-side routines call server routines +directly.\fP +.LP +.NH 1 +\&The C-Preprocessor +.IX rpcgen "C-preprocessor" \fIrpcgen\fP +.LP +The C-preprocessor is  run on all input  files before they are +compiled, so all the preprocessor directives are legal within a \*Q.x\*U +file. Four symbols may be defined, depending upon which output file is +getting generated. The symbols are: +.TS +box tab (&); +lfI lfI +lfL l . +Symbol&Usage +_ +RPC_HDR&for header-file output +RPC_XDR&for XDR routine output +RPC_SVC&for server-skeleton output +RPC_CLNT&for client stub output +.TE +.LP +Also,  +.I rpcgen  +does  a little preprocessing   of its own. Any  line that +begins  with  a percent sign is passed  directly into the output file, +without any interpretation of the line.  Here is a simple example that +demonstrates the preprocessing features. +.ie t .DS +.el .DS L +.ft I +/* + * time.x: Remote time protocol + */ +.ft CW +program TIMEPROG { +        version TIMEVERS { +                unsigned int TIMEGET(void) = 1; +        } = 1; +} = 44; + +#ifdef RPC_SVC +%int * +%timeget_1() +%{ +%        static int thetime; +% +%        thetime = time(0); +%        return (&thetime); +%} +#endif +.DE +The '%' feature is not generally recommended, as there is no guarantee +that the compiler will stick the output where you intended. +.NH 1 +\&\fBrpcgen\fP Programming Notes +.IX rpcgen "other operations" \fIrpcgen\fP +.sp  +.NH 2 +\&Timeout Changes +.IX rpcgen "timeout changes" \fIrpcgen\fP +.LP +RPC sets a default timeout of 25 seconds for RPC calls when +.I clnt_create() +is used.  This timeout may be changed using +.I clnt_control() +Here is a small code fragment to demonstrate use of +.I clnt_control (): +.ID +struct timeval tv; +CLIENT *cl; +.sp .5 +cl = clnt_create("somehost", SOMEPROG, SOMEVERS, "tcp"); +if (cl == NULL) { +	exit(1); +} +tv.tv_sec = 60;	/* \fIchange timeout to 1 minute\fP */ +tv.tv_usec = 0; +clnt_control(cl, CLSET_TIMEOUT, &tv);	 +.DE +.NH 2 +\&Handling Broadcast on the Server Side +.IX "broadcast RPC" +.IX rpcgen "broadcast RPC" \fIrpcgen\fP +.LP +When a procedure is known to be called via broadcast RPC, +it is usually wise for the server to not reply unless it can provide +some useful information to the client.  This prevents the network +from getting flooded by useless replies. +.LP +To prevent the server from replying, a remote procedure can +return NULL as its result, and the server code generated by +.I rpcgen  +will detect this and not send out a reply. +.LP +Here is an example of a procedure that replies only if it +thinks it is an NFS server: +.ID +void * +reply_if_nfsserver() +{ +	char notnull;	/* \fIjust here so we can use its address\fP */ +.sp .5 +	if (access("/etc/exports", F_OK) < 0) { +		return (NULL);	/* \fIprevent RPC from replying\fP */ +	} +.ft I +	/* +	 * return non-null pointer so RPC will send out a reply +	 */ +.ft L +	return ((void *)¬null); +} +.DE +Note that if procedure returns type \*Qvoid *\*U, they must return a non-NULL +pointer if they want RPC to reply for them. +.NH 2 +\&Other Information Passed to Server Procedures +.LP +Server procedures will often want to know more about an RPC call +than just its arguments.  For example, getting authentication information +is important to procedures that want to implement some level of security. +This extra information is actually supplied to the server procedure as a +second argument.  Here is an example to demonstrate its use.  What we've +done here is rewrite the previous +.I printmessage_1()  +procedure to only allow root users to print a message to the console. +.ID +int * +printmessage_1(msg, rq) +	char **msg; +	struct svc_req	*rq; +{ +	static in result;	/* \fIMust be static\fP */ +	FILE *f; +	struct suthunix_parms *aup; +.sp .5 +	aup = (struct authunix_parms *)rq->rq_clntcred; +	if (aup->aup_uid != 0) { +		result = 0; +		return (&result); +	} +.sp +.ft I +	/* +	 * Same code as before. +	 */ +.ft L +} +.DE +.NH 1 +\&RPC Language +.IX RPCL +.IX rpcgen "RPC Language" \fIrpcgen\fP +.LP +RPC language is an extension of XDR  language.   The sole extension is +the addition of the +.I program  +type.  For a complete description of the XDR language syntax, see the +.I "External Data Representation Standard: Protocol Specification" +chapter.  For a description of the RPC extensions to the XDR language, +see the +.I "Remote Procedure Calls: Protocol Specification" +chapter. +.LP +However, XDR language is so close to C that if you know C, you know most +of it already.  We describe here  the syntax of the RPC language, +showing a  few examples along the way.   We also show how  the various +RPC and XDR type definitions get  compiled into C  type definitions in +the output header file. +.KS +.NH 2 +Definitions +\& +.IX rpcgen definitions \fIrpcgen\fP +.LP +An RPC language file consists of a series of definitions. +.DS L +.ft CW +    definition-list: +        definition ";" +        definition ";" definition-list +.DE +.KE +It recognizes five types of definitions.  +.DS L +.ft CW +    definition: +        enum-definition +        struct-definition +        union-definition +        typedef-definition +        const-definition +        program-definition +.DE +.NH 2 +Structures +\& +.IX rpcgen structures \fIrpcgen\fP +.LP +An XDR struct  is declared almost exactly like  its C counterpart.  It +looks like the following: +.DS L +.ft CW +    struct-definition: +        "struct" struct-ident "{" +            declaration-list +        "}" + +    declaration-list: +        declaration ";" +        declaration ";" declaration-list +.DE +As an example, here is an XDR structure to a two-dimensional +coordinate, and the C structure  that it  gets compiled into  in the +output header file. +.DS +.ft CW +   struct coord {             struct coord { +        int x;       -->           int x; +        int y;                     int y; +   };                         }; +                              typedef struct coord coord; +.DE +The output is identical to the  input, except  for the added +.I typedef +at the end of the output.  This allows one to use \*Qcoord\*U instead of +\*Qstruct coord\*U when declaring items. +.NH 2 +Unions +\& +.IX rpcgen unions \fIrpcgen\fP +.LP +XDR unions are discriminated unions, and look quite different from C +unions. They are more analogous to  Pascal variant records than they +are to C unions. +.DS L +.ft CW +    union-definition: +        "union" union-ident "switch" "(" declaration ")" "{" +            case-list +        "}" + +    case-list: +        "case" value ":" declaration ";" +        "default" ":" declaration ";" +        "case" value ":" declaration ";" case-list +.DE +Here is an example of a type that might be returned as the result of a +\*Qread data\*U operation.  If there is no error, return a block of data. +Otherwise, don't return anything. +.DS L +.ft CW +    union read_result switch (int errno) { +    case 0: +        opaque data[1024]; +    default: +        void; +    }; +.DE +It gets compiled into the following: +.DS L +.ft CW +    struct read_result { +        int errno; +        union { +            char data[1024]; +        } read_result_u; +    }; +    typedef struct read_result read_result; +.DE +Notice that the union component of the  output struct  has the name as +the type name, except for the trailing \*Q_u\*U. +.NH 2 +Enumerations +\& +.IX rpcgen enumerations \fIrpcgen\fP +.LP +XDR enumerations have the same syntax as C enumerations. +.DS L +.ft CW +    enum-definition: +        "enum" enum-ident "{" +            enum-value-list +        "}" + +    enum-value-list: +        enum-value +        enum-value "," enum-value-list + +    enum-value: +        enum-value-ident  +        enum-value-ident "=" value +.DE +Here is a short example of  an XDR enum,  and the C enum that  it gets +compiled into. +.DS L +.ft CW +     enum colortype {      enum colortype { +          RED = 0,              RED = 0, +          GREEN = 1,   -->      GREEN = 1, +          BLUE = 2              BLUE = 2, +     };                    }; +                           typedef enum colortype colortype; +.DE +.NH 2 +Typedef +\& +.IX rpcgen typedef \fIrpcgen\fP +.LP +XDR typedefs have the same syntax as C typedefs. +.DS L +.ft CW +    typedef-definition: +        "typedef" declaration +.DE +Here  is an example  that defines a   +.I fname_type  +used  for declaring +file name strings that have a maximum length of 255 characters. +.DS L +.ft CW +typedef string fname_type<255>; --> typedef char *fname_type; +.DE +.NH 2 +Constants +\& +.IX rpcgen constants \fIrpcgen\fP +.LP +XDR constants  symbolic constants  that may be  used wherever  a +integer constant is used, for example, in array size specifications. +.DS L +.ft CW +    const-definition: +        "const" const-ident "=" integer +.DE +For example, the following defines a constant +.I DOZEN  +equal to 12. +.DS L +.ft CW +    const DOZEN = 12;  -->  #define DOZEN 12 +.DE +.NH 2 +Programs +\& +.IX rpcgen programs \fIrpcgen\fP +.LP +RPC programs are declared using the following syntax: +.DS L +.ft CW +    program-definition: +        "program" program-ident "{"  +            version-list +        "}" "=" value  + +    version-list: +        version ";" +        version ";" version-list + +    version: +        "version" version-ident "{" +            procedure-list  +        "}" "=" value + +    procedure-list: +        procedure ";" +        procedure ";" procedure-list + +    procedure: +        type-ident procedure-ident "(" type-ident ")" "=" value +.DE +For example, here is the time protocol, revisited: +.ie t .DS +.el .DS L +.ft I +/* + * time.x: Get or set the time. Time is represented as number of seconds + * since 0:00, January 1, 1970. + */ +.ft CW +program TIMEPROG { +    version TIMEVERS { +        unsigned int TIMEGET(void) = 1; +        void TIMESET(unsigned) = 2; +    } = 1; +} = 44;         +.DE +This file compiles into #defines in the output header file: +.ie t .DS +.el .DS L +.ft CW +#define TIMEPROG 44 +#define TIMEVERS 1 +#define TIMEGET 1 +#define TIMESET 2 +.DE +.NH 2 +Declarations +\& +.IX rpcgen declarations \fIrpcgen\fP +.LP +In XDR, there are only four kinds of declarations.   +.DS L +.ft CW +    declaration: +        simple-declaration +        fixed-array-declaration +        variable-array-declaration +        pointer-declaration +.DE +\fB1) Simple declarations\fP are just like simple C declarations. +.DS L +.ft CW +    simple-declaration: +        type-ident variable-ident +.DE +Example: +.DS L +.ft CW +    colortype color;    --> colortype color; +.DE +\fB2) Fixed-length Array Declarations\fP are just like C array declarations: +.DS L +.ft CW +    fixed-array-declaration: +        type-ident variable-ident "[" value "]" +.DE +Example: +.DS L +.ft CW +    colortype palette[8];    --> colortype palette[8]; +.DE +\fB3) Variable-Length Array Declarations\fP have no explicit syntax  +in C, so XDR invents its own using angle-brackets. +.DS L +.ft CW +variable-array-declaration: +    type-ident variable-ident "<" value ">" +    type-ident variable-ident "<" ">" +.DE +The maximum size is specified between the angle brackets. The size may +be omitted, indicating that the array may be of any size. +.DS L +.ft CW +    int heights<12>;    /* \fIat most 12 items\fP */ +    int widths<>;       /* \fIany number of items\fP */ +.DE +Since  variable-length  arrays have no  explicit  syntax in  C,  these +declarations are actually compiled into \*Qstruct\*Us.  For example, the +\*Qheights\*U declaration gets compiled into the following struct: +.DS L +.ft CW +    struct { +        u_int heights_len;  /* \fI# of items in array\fP */ +        int *heights_val;   /* \fIpointer to array\fP */ +    } heights; +.DE +Note that the number of items in the array is stored in the \*Q_len\*U +component and the pointer to the array is stored in the \*Q_val\*U +component. The first part of each of these component's names is the +same as the name of the declared XDR variable. +.LP +\fB4) Pointer Declarations\fP are made in  +XDR  exactly as they  are  in C.  You  can't +really send pointers over the network,  but  you  can use XDR pointers +for sending recursive data types such as lists and trees.  The type is +actually called \*Qoptional-data\*U, not \*Qpointer\*U, in XDR language. +.DS L +.ft CW +    pointer-declaration: +        type-ident "*" variable-ident +.DE +Example: +.DS L +.ft CW +    listitem *next;  -->  listitem *next; +.DE +.NH 2 +\&Special Cases +.IX rpcgen "special cases" \fIrpcgen\fP +.LP +There are a few exceptions to the rules described above. +.LP +.B Booleans: +C has no built-in boolean type. However, the RPC library does  a +boolean type   called  +.I bool_t  +that   is either   +.I TRUE  +or   +.I FALSE . +Things declared as  type  +.I bool  +in  XDR language  are  compiled  into +.I bool_t  +in the output header file. +.LP +Example: +.DS L +.ft CW +    bool married;  -->  bool_t married; +.DE +.B Strings: +C has  no built-in string  type, but  instead uses the null-terminated +\*Qchar *\*U convention.  In XDR language, strings are declared using the +\*Qstring\*U keyword, and compiled into \*Qchar *\*Us in the output header +file. The  maximum size contained  in the angle brackets specifies the +maximum number of characters allowed in the  strings (not counting the +.I NULL  +character). The maximum size may be left off, indicating a string +of arbitrary length. +.LP +Examples: +.DS L +.ft CW +    string name<32>;    -->  char *name; +    string longname<>;  -->  char *longname; +.DE +.B "Opaque  Data:" +Opaque data is used in RPC and XDR to describe untyped  data, that is, +just  sequences of arbitrary  bytes.  It may be  declared  either as a +fixed or variable length array. +.DS L +Examples: +.ft CW +    opaque diskblock[512];  -->  char diskblock[512]; + +    opaque filedata<1024>;  -->  struct { +                                    u_int filedata_len; +                                    char *filedata_val; +                                 } filedata; +.DE +.B Voids: +In a void declaration, the variable is  not named.  The declaration is +just \*Qvoid\*U and nothing else.  Void declarations can only occur in two +places: union definitions and program definitions (as the  argument or +result of a remote procedure). diff --git a/lib/librpc/doc/xdr.nts.ms b/lib/librpc/doc/xdr.nts.ms new file mode 100644 index 000000000000..6c2d482dea7f --- /dev/null +++ b/lib/librpc/doc/xdr.nts.ms @@ -0,0 +1,1966 @@ +.\" +.\" Must use --  eqn -- with this one +.\" +.\" @(#)xdr.nts.ms	2.2 88/08/05 4.0 RPCSRC +.EQ +delim $$ +.EN +.de BT +.if \\n%=1 .tl ''- % -'' +.. +.ND +.\" prevent excess underlining in nroff +.if n .fp 2 R +.OH 'External Data Representation: Sun Technical Notes''Page %' +.EH 'Page %''External Data Representation: Sun Technical Notes' +.if \\n%=1 .bp +.SH +\&External Data Representation: Sun Technical Notes +.IX XDR "Sun technical notes" +.LP +This chapter contains technical notes on Sun's implementation of the +External Data Representation (XDR) standard, a set of library routines +that allow a C programmer to describe arbitrary data structures in a +machinex-independent fashion.   +For a formal specification of the XDR +standard, see the +.I "External Data Representation Standard: Protocol Specification". +XDR is the backbone of Sun's Remote Procedure Call package, in the  +sense that data for remote procedure calls is transmitted using the  +standard.  XDR library routines should be used to transmit data +that is accessed (read or written) by more than one type of machine.\** +.FS +.IX XDR "system routines" +For a compete specification of the system External Data Representation +routines, see the  +.I xdr(3N)  +manual page. +.FE +.LP +This chapter contains a short tutorial overview of the XDR library  +routines, a guide to accessing currently available XDR streams, and +information on defining new streams and data types.  XDR was designed +to work across different languages, operating systems, and machine  +architectures.  Most users (particularly RPC users) will only need +the information in the +.I "Number Filters", +.I "Floating Point Filters", +and +.I "Enumeration Filters" +sections.   +Programmers wishing to implement RPC and XDR on new machines +will be interested in the rest of the chapter, as well as the +.I "External Data Representaiton Standard: Protocol Specification", +which will be their primary reference. +.SH +Note: +.I +.I rpcgen  +can be used to write XDR routines even in cases where no RPC calls are +being made. +.LP +On Sun systems, +C programs that want to use XDR routines +must include the file +.I <rpc/rpc.h> , +which contains all the necessary interfaces to the XDR system. +Since the C library +.I libc.a +contains all the XDR routines, +compile as normal. +.DS +example% \fBcc\0\fIprogram\fP.c\fI +.DE +.ne 3i +.NH 0 +\&Justification +.IX XDR justification +.LP +Consider the following two programs, +.I writer : +.ie t .DS +.el .DS L +.ft CW +#include <stdio.h> +.sp.5 +main()			/* \fIwriter.c\fP */ +{ +	long i; +.sp.5 +	for (i = 0; i < 8; i++) { +		if (fwrite((char *)&i, sizeof(i), 1, stdout) != 1) { +			fprintf(stderr, "failed!\en"); +			exit(1); +		} +	} +	exit(0); +} +.DE +and +.I reader : +.ie t .DS +.el .DS L +.ft CW +#include <stdio.h> +.sp.5 +main()			/* \fIreader.c\fP */ +{ +	long i, j; +.sp.5 +	for (j = 0; j < 8; j++) { +		if (fread((char *)&i, sizeof (i), 1, stdin) != 1) { +			fprintf(stderr, "failed!\en"); +			exit(1); +		} +		printf("%ld ", i); +	} +	printf("\en"); +	exit(0); +} +.DE +The two programs appear to be portable, because (a) they pass +.I lint +checking, and (b) they exhibit the same behavior when executed +on two different hardware architectures, a Sun and a VAX. +.LP +Piping the output of the +.I writer  +program to the +.I reader  +program gives identical results on a Sun or a VAX. +.DS +.ft CW +sun% \fBwriter | reader\fP +0 1 2 3 4 5 6 7 +sun% + + +vax% \fBwriter | reader\fP +0 1 2 3 4 5 6 7 +vax% +.DE +With the advent of local area networks and 4.2BSD came the concept  +of \*Qnetwork pipes\*U \(em a process produces data on one machine, +and a second process consumes data on another machine. +A network pipe can be constructed with +.I writer  +and +.I reader . +Here are the results if the first produces data on a Sun, +and the second consumes data on a VAX. +.DS +.ft CW +sun% \fBwriter | rsh vax reader\fP +0 16777216 33554432 50331648 67108864 83886080 100663296 +117440512 +sun% +.DE +Identical results can be obtained by executing +.I writer  +on the VAX and +.I reader  +on the Sun.  These results occur because the byte ordering +of long integers differs between the VAX and the Sun, +even though word size is the same. +Note that $16777216$ is $2 sup 24$ \(em +when four bytes are reversed, the 1 winds up in the 24th bit. +.LP +Whenever data is shared by two or more machine types, there is +a need for portable data.  Programs can be made data-portable by +replacing the +.I read()  +and +.I write()  +calls with calls to an XDR library routine +.I xdr_long() , +a filter that knows the standard representation +of a long integer in its external form. +Here are the revised versions of +.I writer : +.ie t .DS +.el .DS L +.ft CW +#include <stdio.h> +#include <rpc/rpc.h>	/* \fIxdr is a sub-library of rpc\fP */ +.sp.5 +main()		/* \fIwriter.c\fP */ +{ +	XDR xdrs; +	long i; +.sp.5 +	xdrstdio_create(&xdrs, stdout, XDR_ENCODE); +	for (i = 0; i < 8; i++) { +		if (!xdr_long(&xdrs, &i)) { +			fprintf(stderr, "failed!\en"); +			exit(1); +		} +	} +	exit(0); +} +.DE +and +.I reader : +.ie t .DS +.el .DS L +.ft CW +#include <stdio.h> +#include <rpc/rpc.h>	/* \fIxdr is a sub-library of rpc\fP */ +.sp.5 +main()		/* \fIreader.c\fP */ +{ +	XDR xdrs; +	long i, j; +.sp.5 +	xdrstdio_create(&xdrs, stdin, XDR_DECODE); +	for (j = 0; j < 8; j++) { +		if (!xdr_long(&xdrs, &i)) { +			fprintf(stderr, "failed!\en"); +			exit(1); +		} +		printf("%ld ", i); +	} +	printf("\en"); +	exit(0); +} +.DE +The new programs were executed on a Sun, +on a VAX, and from a Sun to a VAX; +the results are shown below. +.DS +.ft CW +sun% \fBwriter | reader\fP +0 1 2 3 4 5 6 7 +sun% + +vax% \fBwriter | reader\fP +0 1 2 3 4 5 6 7 +vax% + +sun% \fBwriter | rsh vax reader\fP +0 1 2 3 4 5 6 7 +sun% +.DE +.SH +Note: +.I +.IX XDR "portable data" +Integers are just the tip of the portable-data iceberg.  Arbitrary +data structures present portability problems, particularly with +respect to alignment and pointers.  Alignment on word boundaries +may cause the size of a structure to vary from machine to machine. +And pointers, which are very convenient to use, have no meaning +outside the machine where they are defined. +.LP +.NH 1 +\&A Canonical Standard +.IX XDR "canonical standard" +.LP +XDR's approach to standardizing data representations is  +.I canonical . +That is, XDR defines a single byte order (Big Endian), a single +floating-point representation (IEEE), and so on.  Any program running on +any machine can use XDR to create portable data by translating its +local representation to the XDR standard representations; similarly, any +program running on any machine can read portable data by translating the +XDR standard representaions to its local equivalents.  The single standard +completely decouples programs that create or send portable data from those +that use or receive portable data.  The advent of a new machine or a new +language has no effect upon the community of existing portable data creators +and users.  A new machine joins this community by being \*Qtaught\*U how to +convert the standard representations and its local representations; the +local representations of other machines are irrelevant.  Conversely, to +existing programs running on other machines, the local representations of +the new machine are also irrelevant; such programs can immediately read +portable data produced by the new machine because such data conforms to the +canonical standards that they already understand. +.LP +There are strong precedents for XDR's canonical approach.  For example, +TCP/IP, UDP/IP, XNS, Ethernet, and, indeed, all protocols below layer five +of the ISO model, are canonical protocols.  The advantage of any canonical  +approach is simplicity; in the case of XDR, a single set of conversion  +routines is written once and is never touched again.  The canonical approach  +has a disadvantage, but it is unimportant in real-world data transfer  +applications.  Suppose two Little-Endian machines are transferring integers +according to the XDR standard.  The sending machine converts the integers  +from Little-Endian byte order to XDR (Big-Endian) byte order; the receiving +machine performs the reverse conversion.  Because both machines observe the +same byte order, their conversions are unnecessary.  The point, however, is +not necessity, but cost as compared to the alternative. +.LP +The time spent converting to and from a canonical representation is +insignificant, especially in networking applications.  Most of the time  +required to prepare a data structure for transfer is not spent in conversion  +but in traversing the elements of the data structure.  To transmit a tree,  +for example, each leaf must be visited and each element in a leaf record must +be copied to a buffer and aligned there; storage for the leaf may have to be +deallocated as well.  Similarly, to receive a tree, storage must be  +allocated for each leaf, data must be moved from the buffer to the leaf and +properly aligned, and pointers must be constructed to link the leaves  +together.  Every machine pays the cost of traversing and copying data +structures whether or not conversion is required.  In networking  +applications, communications overhead\(emthe time required to move the data +down through the sender's protocol layers, across the network and up through  +the receiver's protocol layers\(emdwarfs conversion overhead. +.NH 1 +\&The XDR Library +.IX "XDR" "library" +.LP +The XDR library not only solves data portability problems, it also +allows you to write and read arbitrary C constructs in a consistent,  +specified, well-documented manner.  Thus, it can make sense to use the  +library even when the data is not shared among machines on a network. +.LP +The XDR library has filter routines for +strings (null-terminated arrays of bytes), +structures, unions, and arrays, to name a few. +Using more primitive routines, +you can write your own specific XDR routines +to describe arbitrary data structures, +including elements of arrays, arms of unions, +or objects pointed at from other structures. +The structures themselves may contain arrays of arbitrary elements, +or pointers to other structures. +.LP +Let's examine the two programs more closely. +There is a family of XDR stream creation routines +in which each member treats the stream of bits differently. +In our example, data is manipulated using standard I/O routines, +so we use +.I xdrstdio_create (). +.IX xdrstdio_create() "" "\fIxdrstdio_create()\fP" +The parameters to XDR stream creation routines +vary according to their function. +In our example, +.I xdrstdio_create()  +takes a pointer to an XDR structure that it initializes, +a pointer to a +.I FILE  +that the input or output is performed on, and the operation. +The operation may be +.I XDR_ENCODE +for serializing in the +.I writer  +program, or +.I XDR_DECODE +for deserializing in the +.I reader  +program. +.LP +Note: RPC users never need to create XDR streams; +the RPC system itself creates these streams, +which are then passed to the users. +.LP +The +.I xdr_long()  +.IX xdr_long() "" "\fIxdr_long()\fP" +primitive is characteristic of most XDR library  +primitives and all client XDR routines. +First, the routine returns +.I FALSE  +(0) if it fails, and +.I TRUE  +(1) if it succeeds. +Second, for each data type, +.I xxx , +there is an associated XDR routine of the form: +.DS +.ft CW +xdr_xxx(xdrs, xp) +	XDR *xdrs; +	xxx *xp; +{ +} +.DE +In our case, +.I xxx  +is long, and the corresponding XDR routine is +a primitive, +.I xdr_long() . +The client could also define an arbitrary structure +.I xxx  +in which case the client would also supply the routine +.I xdr_xxx (), +describing each field by calling XDR routines +of the appropriate type. +In all cases the first parameter, +.I xdrs  +can be treated as an opaque handle, +and passed to the primitive routines. +.LP +XDR routines are direction independent; +that is, the same routines are called to serialize or deserialize data. +This feature is critical to software engineering of portable data. +The idea is to call the same routine for either operation \(em +this almost guarantees that serialized data can also be deserialized. +One routine is used by both producer and consumer of networked data. +This is implemented by always passing the address +of an object rather than the object itself \(em +only in the case of deserialization is the object modified. +This feature is not shown in our trivial example, +but its value becomes obvious when nontrivial data structures +are passed among machines.   +If needed, the user can obtain the +direction of the XDR operation.   +See the +.I "XDR Operation Directions" +section below for details. +.LP +Let's look at a slightly more complicated example. +Assume that a person's gross assets and liabilities +are to be exchanged among processes. +Also assume that these values are important enough +to warrant their own data type: +.ie t .DS +.el .DS L +.ft CW +struct gnumbers { +	long g_assets; +	long g_liabilities; +}; +.DE +The corresponding XDR routine describing this structure would be: +.ie t .DS +.el .DS L +.ft CW +bool_t  		/* \fITRUE is success, FALSE is failure\fP */ +xdr_gnumbers(xdrs, gp) +	XDR *xdrs; +	struct gnumbers *gp; +{ +	if (xdr_long(xdrs, &gp->g_assets) && +	    xdr_long(xdrs, &gp->g_liabilities)) +		return(TRUE); +	return(FALSE); +} +.DE +Note that the parameter +.I xdrs  +is never inspected or modified; +it is only passed on to the subcomponent routines. +It is imperative to inspect the return value of each XDR routine call, +and to give up immediately and return +.I FALSE  +if the subroutine fails. +.LP +This example also shows that the type +.I bool_t +is declared as an integer whose only values are +.I TRUE  +(1) and +.I FALSE  +(0).  This document uses the following definitions: +.ie t .DS +.el .DS L +.ft CW +#define bool_t	int +#define TRUE	1 +#define FALSE	0 +.DE +.LP +Keeping these conventions in mind, +.I xdr_gnumbers()  +can be rewritten as follows: +.ie t .DS +.el .DS L +.ft CW +xdr_gnumbers(xdrs, gp) +	XDR *xdrs; +	struct gnumbers *gp; +{ +	return(xdr_long(xdrs, &gp->g_assets) && +		xdr_long(xdrs, &gp->g_liabilities)); +} +.DE +This document uses both coding styles. +.NH 1 +\&XDR Library Primitives +.IX "library primitives for XDR" +.IX XDR "library primitives" +.LP +This section gives a synopsis of each XDR primitive. +It starts with basic data types and moves on to constructed data types. +Finally, XDR utilities are discussed. +The interface to these primitives +and utilities is defined in the include file +.I <rpc/xdr.h> , +automatically included by +.I <rpc/rpc.h> . +.NH 2 +\&Number Filters +.IX "XDR library" "number filters" +.LP +The XDR library provides primitives to translate between numbers +and their corresponding external representations. +Primitives cover the set of numbers in: +.DS +.ft CW +[signed, unsigned] * [short, int, long] +.DE +.ne 2i +Specifically, the eight primitives are: +.DS +.ft CW +bool_t xdr_char(xdrs, cp) +	XDR *xdrs; +	char *cp; +.sp.5 +bool_t xdr_u_char(xdrs, ucp) +	XDR *xdrs; +	unsigned char *ucp; +.sp.5 +bool_t xdr_int(xdrs, ip) +	XDR *xdrs; +	int *ip; +.sp.5 +bool_t xdr_u_int(xdrs, up) +	XDR *xdrs; +	unsigned *up; +.sp.5 +bool_t xdr_long(xdrs, lip) +	XDR *xdrs; +	long *lip; +.sp.5 +bool_t xdr_u_long(xdrs, lup) +	XDR *xdrs; +	u_long *lup; +.sp.5 +bool_t xdr_short(xdrs, sip) +	XDR *xdrs; +	short *sip; +.sp.5 +bool_t xdr_u_short(xdrs, sup) +	XDR *xdrs; +	u_short *sup; +.DE +The first parameter, +.I xdrs , +is an XDR stream handle. +The second parameter is the address of the number +that provides data to the stream or receives data from it. +All routines return +.I TRUE  +if they complete successfully, and +.I FALSE  +otherwise. +.NH 2 +\&Floating Point Filters +.IX "XDR library" "floating point filters" +.LP +The XDR library also provides primitive routines +for C's floating point types: +.DS +.ft CW +bool_t xdr_float(xdrs, fp) +	XDR *xdrs; +	float *fp; +.sp.5 +bool_t xdr_double(xdrs, dp) +	XDR *xdrs; +	double *dp; +.DE +The first parameter, +.I xdrs  +is an XDR stream handle. +The second parameter is the address +of the floating point number that provides data to the stream +or receives data from it. +Both routines return +.I TRUE  +if they complete successfully, and +.I FALSE  +otherwise. +.LP +Note: Since the numbers are represented in IEEE floating point, +routines may fail when decoding a valid IEEE representation +into a machine-specific representation, or vice-versa. +.NH 2 +\&Enumeration Filters +.IX "XDR library" "enumeration filters" +.LP +The XDR library provides a primitive for generic enumerations. +The primitive assumes that a C +.I enum  +has the same representation inside the machine as a C integer. +The boolean type is an important instance of the +.I enum . +The external representation of a boolean is always +.I TRUE  +(1) or  +.I FALSE  +(0). +.DS +.ft CW +#define bool_t	int +#define FALSE	0 +#define TRUE	1 +.sp.5 +#define enum_t int +.sp.5 +bool_t xdr_enum(xdrs, ep) +	XDR *xdrs; +	enum_t *ep; +.sp.5 +bool_t xdr_bool(xdrs, bp) +	XDR *xdrs; +	bool_t *bp; +.DE +The second parameters +.I ep +and +.I bp +are addresses of the associated type that provides data to, or  +receives data from, the stream +.I xdrs . +.NH 2 +\&No Data +.IX "XDR library" "no data" +.LP +Occasionally, an XDR routine must be supplied to the RPC system, +even when no data is passed or required. +The library provides such a routine: +.DS +.ft CW +bool_t xdr_void();  /* \fIalways returns TRUE\fP */ +.DE +.NH 2 +\&Constructed Data Type Filters +.IX "XDR library" "constructed data type filters" +.LP +Constructed or compound data type primitives +require more parameters and perform more complicated functions +then the primitives discussed above. +This section includes primitives for +strings, arrays, unions, and pointers to structures. +.LP +Constructed data type primitives may use memory management. +In many cases, memory is allocated when deserializing data with +.I XDR_DECODE +Therefore, the XDR package must provide means to deallocate memory. +This is done by an XDR operation, +.I XDR_FREE +To review, the three XDR directional operations are +.I XDR_ENCODE , +.I XDR_DECODE +and +.I XDR_FREE . +.NH 3 +\&Strings +.IX "XDR library" "strings" +.LP +In C, a string is defined as a sequence of bytes +terminated by a null byte, +which is not considered when calculating string length. +However, when a string is passed or manipulated, +a pointer to it is employed. +Therefore, the XDR library defines a string to be a +.I "char *" +and not a sequence of characters. +The external representation of a string is drastically different +from its internal representation. +Externally, strings are represented as +sequences of ASCII characters, +while internally, they are represented with character pointers. +Conversion between the two representations +is accomplished with the routine +.I xdr_string (): +.IX xdr_string() "" \fIxdr_string()\fP +.DS +.ft CW +bool_t xdr_string(xdrs, sp, maxlength) +	XDR *xdrs; +	char **sp; +	u_int maxlength; +.DE +The first parameter +.I xdrs  +is the XDR stream handle. +The second parameter +.I sp  +is a pointer to a string (type +.I "char **" . +The third parameter +.I maxlength  +specifies the maximum number of bytes allowed during encoding or decoding. +its value is usually specified by a protocol.  For example, a protocol +specification may say that a file name may be no longer than 255 characters. +.LP +The routine returns +.I FALSE  +if the number of characters exceeds +.I maxlength , +and +.I TRUE  +if it doesn't. +.SH +Keep +.I maxlength  +small.  If it is too big you can blow the heap, since +.I xdr_string()  +will call +.I malloc()  +for space. +.LP +The behavior of +.I xdr_string()  +.IX xdr_string() "" \fIxdr_string()\fP +is similar to the behavior of other routines +discussed in this section.  The direction +.I XDR_ENCODE  +is easiest to understand.  The parameter +.I sp  +points to a string of a certain length; +if the string does not exceed +.I maxlength , +the bytes are serialized. +.LP +The effect of deserializing a string is subtle. +First the length of the incoming string is determined; +it must not exceed +.I maxlength . +Next +.I sp  +is dereferenced; if the the value is +.I NULL , +then a string of the appropriate length is allocated and +.I *sp  +is set to this string. +If the original value of +.I *sp  +is non-null, then the XDR package assumes +that a target area has been allocated, +which can hold strings no longer than +.I maxlength . +In either case, the string is decoded into the target area. +The routine then appends a null character to the string. +.LP +In the +.I XDR_FREE  +operation, the string is obtained by dereferencing +.I sp . +If the string is not +.I NULL , +it is freed and +.I *sp  +is set to +.I NULL . +In this operation, +.I xdr_string()  +ignores the +.I maxlength  +parameter. +.NH 3 +\&Byte Arrays +.IX "XDR library" "byte arrays" +.LP +Often variable-length arrays of bytes are preferable to strings. +Byte arrays differ from strings in the following three ways:  +1) the length of the array (the byte count) is explicitly +located in an unsigned integer, +2) the byte sequence is not terminated by a null character, and +3) the external representation of the bytes is the same as their +internal representation. +The primitive +.I xdr_bytes()  +.IX xdr_bytes() "" \fIxdr_bytes()\fP +converts between the internal and external +representations of byte arrays: +.DS +.ft CW +bool_t xdr_bytes(xdrs, bpp, lp, maxlength) +    XDR *xdrs; +    char **bpp; +    u_int *lp; +    u_int maxlength; +.DE +The usage of the first, second and fourth parameters +are identical to the first, second and third parameters of +.I xdr_string (), +respectively. +The length of the byte area is obtained by dereferencing +.I lp  +when serializing; +.I *lp  +is set to the byte length when deserializing. +.NH 3 +\&Arrays +.IX "XDR library" "arrays" +.LP +The XDR library package provides a primitive +for handling arrays of arbitrary elements. +The +.I xdr_bytes()  +routine treats a subset of generic arrays, +in which the size of array elements is known to be 1, +and the external description of each element is built-in. +The generic array primitive, +.I xdr_array() , +.IX xdr_array() "" \fIxdr_array()\fP +requires parameters identical to those of +.I xdr_bytes()  +plus two more: +the size of array elements, +and an XDR routine to handle each of the elements. +This routine is called to encode or decode +each element of the array. +.DS +.ft CW +bool_t +xdr_array(xdrs, ap, lp, maxlength, elementsiz, xdr_element) +    XDR *xdrs; +    char **ap; +    u_int *lp; +    u_int maxlength; +    u_int elementsiz; +    bool_t (*xdr_element)(); +.DE +The parameter +.I ap  +is the address of the pointer to the array. +If +.I *ap  +is +.I NULL  +when the array is being deserialized, +XDR allocates an array of the appropriate size and sets +.I *ap  +to that array. +The element count of the array is obtained from +.I *lp  +when the array is serialized; +.I *lp  +is set to the array length when the array is deserialized.  +The parameter +.I maxlength  +is the maximum number of elements that the array is allowed to have; +.I elementsiz +is the byte size of each element of the array +(the C function +.I sizeof() +can be used to obtain this value). +The +.I xdr_element()  +.IX xdr_element() "" \fIxdr_element()\fP +routine is called to serialize, deserialize, or free +each element of the array. +.br +.LP +Before defining more constructed data types, it is appropriate to  +present three examples. +.LP +.I "Example A:" +.br +A user on a networked machine can be identified by  +(a) the machine name, such as +.I krypton : +see the +.I gethostname  +man page; (b) the user's UID: see the +.I geteuid  +man page; and (c) the group numbers to which the user belongs:  +see the +.I getgroups  +man page.  A structure with this information and its associated  +XDR routine could be coded like this: +.ie t .DS +.el .DS L +.ft CW +struct netuser { +    char    *nu_machinename; +    int     nu_uid; +    u_int   nu_glen; +    int     *nu_gids; +}; +#define NLEN 255    /* \fImachine names < 256 chars\fP */ +#define NGRPS 20    /* \fIuser can't be in > 20 groups\fP */ +.sp.5 +bool_t +xdr_netuser(xdrs, nup) +    XDR *xdrs; +    struct netuser *nup; +{ +    return(xdr_string(xdrs, &nup->nu_machinename, NLEN) && +        xdr_int(xdrs, &nup->nu_uid) && +        xdr_array(xdrs, &nup->nu_gids, &nup->nu_glen,  +        NGRPS, sizeof (int), xdr_int)); +} +.DE +.LP +.I "Example B:" +.br +A party of network users could be implemented +as an array of +.I netuser +structure. +The declaration and its associated XDR routines +are as follows: +.ie t .DS +.el .DS L +.ft CW +struct party { +    u_int p_len; +    struct netuser *p_nusers; +}; +#define PLEN 500    /* \fImax number of users in a party\fP */ +.sp.5 +bool_t +xdr_party(xdrs, pp) +    XDR *xdrs; +    struct party *pp; +{ +    return(xdr_array(xdrs, &pp->p_nusers, &pp->p_len, PLEN, +        sizeof (struct netuser), xdr_netuser)); +} +.DE +.LP +.I "Example C:" +.br +The well-known parameters to +.I main , +.I argc +and +.I argv +can be combined into a structure. +An array of these structures can make up a history of commands. +The declarations and XDR routines might look like: +.ie t .DS +.el .DS L +.ft CW +struct cmd { +    u_int c_argc; +    char **c_argv; +}; +#define ALEN 1000   /* \fIargs cannot be > 1000 chars\fP */ +#define NARGC 100   /* \fIcommands cannot have > 100 args\fP */ + +struct history { +    u_int h_len; +    struct cmd *h_cmds; +}; +#define NCMDS 75    /* \fIhistory is no more than 75 commands\fP */ + +bool_t +xdr_wrap_string(xdrs, sp) +    XDR *xdrs; +    char **sp; +{ +    return(xdr_string(xdrs, sp, ALEN)); +} +.DE +.ie t .DS +.el .DS L +.ft CW +bool_t +xdr_cmd(xdrs, cp) +    XDR *xdrs; +    struct cmd *cp; +{ +    return(xdr_array(xdrs, &cp->c_argv, &cp->c_argc, NARGC, +        sizeof (char *), xdr_wrap_string)); +} +.DE +.ie t .DS +.el .DS L +.ft CW +bool_t +xdr_history(xdrs, hp) +    XDR *xdrs; +    struct history *hp; +{ +    return(xdr_array(xdrs, &hp->h_cmds, &hp->h_len, NCMDS, +        sizeof (struct cmd), xdr_cmd)); +} +.DE +The most confusing part of this example is that the routine +.I xdr_wrap_string()  +is needed to package the +.I xdr_string()  +routine, because the implementation of +.I xdr_array()  +only passes two parameters to the array element description routine; +.I xdr_wrap_string()  +supplies the third parameter to +.I xdr_string (). +.LP +By now the recursive nature of the XDR library should be obvious. +Let's continue with more constructed data types. +.NH 3 +\&Opaque Data +.IX "XDR library" "opaque data" +.LP +In some protocols, handles are passed from a server to client. +The client passes the handle back to the server at some later time. +Handles are never inspected by clients; +they are obtained and submitted. +That is to say, handles are opaque. +The +.I xdr_opaque()  +.IX xdr_opaque() "" \fIxdr_opaque()\fP +primitive is used for describing fixed sized, opaque bytes. +.DS +.ft CW +bool_t xdr_opaque(xdrs, p, len) +    XDR *xdrs; +    char *p; +    u_int len; +.DE +The parameter +.I p  +is the location of the bytes; +.I len +is the number of bytes in the opaque object. +By definition, the actual data +contained in the opaque object are not machine portable. +.NH 3 +\&Fixed Sized Arrays +.IX "XDR library" "fixed sized arrays" +.LP +The XDR library provides a primitive, +.I xdr_vector (), +for fixed-length arrays. +.ie t .DS +.el .DS L +.ft CW +#define NLEN 255    /* \fImachine names must be < 256 chars\fP */ +#define NGRPS 20    /* \fIuser belongs to exactly 20 groups\fP */ +.sp.5 +struct netuser { +    char *nu_machinename; +    int nu_uid; +    int nu_gids[NGRPS]; +}; +.sp.5 +bool_t +xdr_netuser(xdrs, nup) +    XDR *xdrs; +    struct netuser *nup; +{ +    int i; +.sp.5 +    if (!xdr_string(xdrs, &nup->nu_machinename, NLEN)) +        return(FALSE); +    if (!xdr_int(xdrs, &nup->nu_uid)) +        return(FALSE); +    if (!xdr_vector(xdrs, nup->nu_gids, NGRPS, sizeof(int),  +        xdr_int)) { +            return(FALSE); +    } +    return(TRUE); +} +.DE +.NH 3 +\&Discriminated Unions +.IX "XDR library" "discriminated unions" +.LP +The XDR library supports discriminated unions. +A discriminated union is a C union and an +.I enum_t +value that selects an \*Qarm\*U of the union. +.DS +.ft CW +struct xdr_discrim { +    enum_t value; +    bool_t (*proc)(); +}; +.sp.5 +bool_t xdr_union(xdrs, dscmp, unp, arms, defaultarm) +    XDR *xdrs; +    enum_t *dscmp; +    char *unp; +    struct xdr_discrim *arms; +    bool_t (*defaultarm)();  /* \fImay equal NULL\fP */ +.DE +First the routine translates the discriminant of the union located at  +.I *dscmp . +The discriminant is always an +.I enum_t . +Next the union located at +.I *unp  +is translated. +The parameter +.I arms +is a pointer to an array of +.I xdr_discrim +structures.  +Each structure contains an ordered pair of +.I [value,proc] . +If the union's discriminant is equal to the associated +.I value , +then the +.I proc +is called to translate the union. +The end of the +.I xdr_discrim +structure array is denoted by a routine of value +.I NULL  +(0).  If the discriminant is not found in the +.I arms +array, then the +.I defaultarm +procedure is called if it is non-null; +otherwise the routine returns +.I FALSE . +.LP +.I "Example D:" +Suppose the type of a union may be integer, +character pointer (a string), or a +.I gnumbers  +structure. +Also, assume the union and its current type +are declared in a structure. +The declaration is: +.ie t .DS +.el .DS L +.ft CW +enum utype { INTEGER=1, STRING=2, GNUMBERS=3 }; +.sp.5 +struct u_tag { +    enum utype utype;   /* \fIthe union's discriminant\fP */ +    union { +        int ival; +        char *pval; +        struct gnumbers gn; +    } uval; +}; +.DE +The following constructs and XDR procedure (de)serialize +the discriminated union: +.ie t .DS +.el .DS L +.ft CW +struct xdr_discrim u_tag_arms[4] = { +    { INTEGER, xdr_int }, +    { GNUMBERS, xdr_gnumbers } +    { STRING, xdr_wrap_string }, +    { __dontcare__, NULL } +    /* \fIalways terminate arms with a NULL xdr_proc\fP */ +} +.sp.5 +bool_t +xdr_u_tag(xdrs, utp) +    XDR *xdrs; +    struct u_tag *utp; +{ +    return(xdr_union(xdrs, &utp->utype, &utp->uval, +        u_tag_arms, NULL)); +} +.DE +The routine +.I xdr_gnumbers()  +was presented above in  +.I "The XDR Library" +section. +.I xdr_wrap_string()  +was presented in example C. +The default  +.I arm  +parameter to +.I xdr_union()  +(the last parameter) is +.I NULL  +in this example.  Therefore the value of the union's discriminant +may legally take on only values listed in the +.I u_tag_arms  +array.  This example also demonstrates that +the elements of the arm's array do not need to be sorted. +.LP +It is worth pointing out that the values of the discriminant +may be sparse, though in this example they are not. +It is always good +practice to assign explicitly integer values to each element of the +discriminant's type. +This practice both documents the external +representation of the discriminant and guarantees that different +C compilers emit identical discriminant values. +.LP +Exercise: Implement +.I xdr_union()  +using the other primitives in this section. +.NH 3 +\&Pointers +.IX "XDR library" "pointers" +.LP +In C it is often convenient to put pointers +to another structure within a structure. +The +.I xdr_reference()  +.IX xdr_reference() "" \fIxdr_reference()\fP +primitive makes it easy to serialize, deserialize, and free +these referenced structures. +.DS +.ft CW +bool_t xdr_reference(xdrs, pp, size, proc) +    XDR *xdrs; +    char **pp; +    u_int ssize; +    bool_t (*proc)(); +.DE +.LP +Parameter +.I pp  +is the address of +the pointer to the structure; +parameter +.I ssize +is the size in bytes of the structure (use the C function +.I sizeof()  +to obtain this value); and +.I proc +is the XDR routine that describes the structure. +When decoding data, storage is allocated if +.I *pp  +is +.I NULL . +.LP +There is no need for a primitive +.I xdr_struct()  +to describe structures within structures, +because pointers are always sufficient. +.LP +Exercise: Implement +.I xdr_reference()  +using +.I xdr_array (). +Warning: +.I xdr_reference()  +and +.I xdr_array()  +are NOT interchangeable external representations of data. +.LP +.I "Example E:" +Suppose there is a structure containing a person's name +and a pointer to a +.I gnumbers  +structure containing the person's gross assets and liabilities. +The construct is: +.DS +.ft CW +struct pgn { +    char *name; +    struct gnumbers *gnp; +}; +.DE +The corresponding XDR routine for this structure is: +.DS +.ft CW +bool_t +xdr_pgn(xdrs, pp) +    XDR *xdrs; +    struct pgn *pp; +{ +    if (xdr_string(xdrs, &pp->name, NLEN) && +      xdr_reference(xdrs, &pp->gnp, +      sizeof(struct gnumbers), xdr_gnumbers)) +        return(TRUE); +    return(FALSE); +} +.DE +.IX "pointer semantics and XDR" +.I "Pointer Semantics and XDR"  +.LP +In many applications, C programmers attach double meaning to  +the values of a pointer.  Typically the value +.I NULL  +(or zero) means data is not needed, +yet some application-specific interpretation applies. +In essence, the C programmer is encoding +a discriminated union efficiently +by overloading the interpretation of the value of a pointer. +For instance, in example E a +.I NULL  +pointer value for +.I gnp +could indicate that +the person's assets and liabilities are unknown. +That is, the pointer value encodes two things: +whether or not the data is known; +and if it is known, where it is located in memory. +Linked lists are an extreme example of the use +of application-specific pointer interpretation. +.LP +The primitive +.I xdr_reference()  +.IX xdr_reference() "" \fIxdr_reference()\fP +cannot and does not attach any special +meaning to a null-value pointer during serialization. +That is, passing an address of a pointer whose value is +.I NULL  +to +.I xdr_reference()  +when serialing data will most likely cause a memory fault and, on the UNIX +system, a core dump. +.LP +.I xdr_pointer()  +correctly handles  +.I NULL  +pointers.  For more information about its use, see  +the +.I "Linked Lists" +topics below. +.LP +.I Exercise: +After reading the section on +.I "Linked Lists" , +return here and extend example E so that +it can correctly deal with  +.I NULL  +pointer values. +.LP +.I Exercise: +Using the +.I xdr_union (), +.I xdr_reference()  +and +.I xdr_void()  +primitives, implement a generic pointer handling primitive +that implicitly deals with +.I NULL  +pointers.  That is, implement +.I xdr_pointer (). +.NH 2 +\&Non-filter Primitives +.IX "XDR" "non-filter primitives" +.LP +XDR streams can be manipulated with +the primitives discussed in this section. +.DS +.ft CW +u_int xdr_getpos(xdrs) +    XDR *xdrs; +.sp.5 +bool_t xdr_setpos(xdrs, pos) +    XDR *xdrs; +    u_int pos; +.sp.5 +xdr_destroy(xdrs) +    XDR *xdrs; +.DE +The routine +.I xdr_getpos()  +.IX xdr_getpos() "" \fIxdr_getpos()\fP +returns an unsigned integer +that describes the current position in the data stream. +Warning: In some XDR streams, the returned value of +.I xdr_getpos()  +is meaningless; +the routine returns a \-1 in this case +(though \-1 should be a legitimate value). +.LP +The routine +.I xdr_setpos()  +.IX xdr_setpos() "" \fIxdr_setpos()\fP +sets a stream position to +.I pos . +Warning: In some XDR streams, setting a position is impossible; +in such cases, +.I xdr_setpos()  +will return +.I FALSE . +This routine will also fail if the requested position is out-of-bounds. +The definition of bounds varies from stream to stream. +.LP +The +.I xdr_destroy()  +.IX xdr_destroy() "" \fIxdr_destroy()\fP +primitive destroys the XDR stream. +Usage of the stream +after calling this routine is undefined. +.NH 2 +\&XDR Operation Directions +.IX XDR "operation directions" +.IX "direction of XDR operations" +.LP +At times you may wish to optimize XDR routines by taking +advantage of the direction of the operation \(em +.I XDR_ENCODE +.I XDR_DECODE +or +.I XDR_FREE +The value +.I xdrs->x_op +always contains the direction of the XDR operation. +Programmers are not encouraged to take advantage of this information. +Therefore, no example is presented here.  However, an example in the +.I "Linked Lists" +topic below, demonstrates the usefulness of the +.I xdrs->x_op +field. +.NH 2 +\&XDR Stream Access +.IX "XDR" "stream access" +.LP +An XDR stream is obtained by calling the appropriate creation routine. +These creation routines take arguments that are tailored to the +specific properties of the stream. +.LP +Streams currently exist for (de)serialization of data to or from +standard I/O +.I FILE +streams, TCP/IP connections and UNIX files, and memory. +.NH 3 +\&Standard I/O Streams +.IX "XDR" "standard I/O streams" +.LP +XDR streams can be interfaced to standard I/O using the +.I xdrstdio_create()  +.IX xdrstdio_create() "" \fIxdrstdio_create()\fP +routine as follows: +.DS +.ft CW +#include <stdio.h> +#include <rpc/rpc.h>    /* \fIxdr streams part of rpc\fP */ +.sp.5 +void +xdrstdio_create(xdrs, fp, x_op) +    XDR *xdrs; +    FILE *fp; +    enum xdr_op x_op; +.DE +The routine +.I xdrstdio_create()  +initializes an XDR stream pointed to by +.I xdrs . +The XDR stream interfaces to the standard I/O library. +Parameter +.I fp +is an open file, and +.I x_op +is an XDR direction. +.NH 3 +\&Memory Streams +.IX "XDR" "memory streams" +.LP +Memory streams allow the streaming of data into or out of +a specified area of memory: +.DS +.ft CW +#include <rpc/rpc.h> +.sp.5 +void +xdrmem_create(xdrs, addr, len, x_op) +    XDR *xdrs; +    char *addr; +    u_int len; +    enum xdr_op x_op; +.DE +The routine +.I xdrmem_create()  +.IX xdrmem_create() "" \fIxdrmem_create()\fP +initializes an XDR stream in local memory. +The memory is pointed to by parameter +.I addr ; +parameter +.I len +is the length in bytes of the memory. +The parameters +.I xdrs +and +.I x_op +are identical to the corresponding parameters of +.I xdrstdio_create (). +Currently, the UDP/IP implementation of RPC uses +.I xdrmem_create (). +Complete call or result messages are built in memory before calling the +.I sendto()  +system routine. +.NH 3 +\&Record (TCP/IP) Streams +.IX "XDR" "record (TCP/IP) streams" +.LP +A record stream is an XDR stream built on top of +a record marking standard that is built on top of the +UNIX file or 4.2 BSD connection interface. +.DS +.ft CW +#include <rpc/rpc.h>    /* \fIxdr streams part of rpc\fP */ +.sp.5 +xdrrec_create(xdrs, +  sendsize, recvsize, iohandle, readproc, writeproc) +    XDR *xdrs; +    u_int sendsize, recvsize; +    char *iohandle; +    int (*readproc)(), (*writeproc)(); +.DE +The routine +.I xdrrec_create()  +provides an XDR stream interface that allows for a bidirectional, +arbitrarily long sequence of records. +The contents of the records are meant to be data in XDR form. +The stream's primary use is for interfacing RPC to TCP connections. +However, it can be used to stream data into or out of normal +UNIX files. +.LP +The parameter +.I xdrs +is similar to the corresponding parameter described above. +The stream does its own data buffering similar to that of standard I/O. +The parameters +.I sendsize +and +.I recvsize +determine the size in bytes of the output and input buffers, respectively; +if their values are zero (0), then predetermined defaults are used. +When a buffer needs to be filled or flushed, the routine +.I readproc()  +or +.I writeproc()  +is called, respectively. +The usage and behavior of these +routines are similar to the UNIX system calls +.I read()  +and +.I write (). +However, +the first parameter to each of these routines is the opaque parameter +.I iohandle . +The other two parameters +.I buf "" +and +.I nbytes ) +and the results +(byte count) are identical to the system routines. +If +.I xxx  +is +.I readproc()  +or +.I writeproc (), +then it has the following form: +.DS +.ft CW +.ft I +/* + * returns the actual number of bytes transferred. + * -1 is an error + */ +.ft CW +int +xxx(iohandle, buf, len) +    char *iohandle; +    char *buf; +    int nbytes; +.DE +The XDR stream provides means for delimiting records in the byte stream. +The implementation details of delimiting records in a stream are +discussed in the +.I "Advanced Topics" +topic below. +The primitives that are specific to record streams are as follows: +.DS +.ft CW +bool_t +xdrrec_endofrecord(xdrs, flushnow) +    XDR *xdrs; +    bool_t flushnow; +.sp.5 +bool_t +xdrrec_skiprecord(xdrs) +    XDR *xdrs; +.sp.5 +bool_t +xdrrec_eof(xdrs) +    XDR *xdrs; +.DE +The routine +.I xdrrec_endofrecord()  +.IX xdrrec_endofrecord() "" \fIxdrrec_endofrecord()\fP +causes the current outgoing data to be marked as a record. +If the parameter +.I flushnow +is +.I TRUE , +then the stream's +.I writeproc  +will be called; otherwise, +.I writeproc  +will be called when the output buffer has been filled. +.LP +The routine +.I xdrrec_skiprecord()  +.IX xdrrec_skiprecord() "" \fIxdrrec_skiprecord()\fP +causes an input stream's position to be moved past +the current record boundary and onto the +beginning of the next record in the stream. +.LP +If there is no more data in the stream's input buffer, +then the routine +.I xdrrec_eof()  +.IX xdrrec_eof() "" \fIxdrrec_eof()\fP +returns +.I TRUE . +That is not to say that there is no more data +in the underlying file descriptor. +.NH 2 +\&XDR Stream Implementation +.IX "XDR" "stream implementation" +.IX "stream implementation in XDR" +.LP +This section provides the abstract data types needed +to implement new instances of XDR streams. +.NH 3 +\&The XDR Object +.IX "XDR" "object" +.LP +The following structure defines the interface to an XDR stream: +.ie t .DS +.el .DS L +.ft CW +enum xdr_op { XDR_ENCODE=0, XDR_DECODE=1, XDR_FREE=2 }; +.sp.5 +typedef struct { +    enum xdr_op x_op;            /* \fIoperation; fast added param\fP */ +    struct xdr_ops { +        bool_t  (*x_getlong)();  /* \fIget long from stream\fP */ +        bool_t  (*x_putlong)();  /* \fIput long to stream\fP */ +        bool_t  (*x_getbytes)(); /* \fIget bytes from stream\fP */ +        bool_t  (*x_putbytes)(); /* \fIput bytes to stream\fP */ +        u_int   (*x_getpostn)(); /* \fIreturn stream offset\fP */ +        bool_t  (*x_setpostn)(); /* \fIreposition offset\fP */ +        caddr_t (*x_inline)();   /* \fIptr to buffered data\fP */ +        VOID    (*x_destroy)();  /* \fIfree private area\fP */ +    } *x_ops; +    caddr_t     x_public;        /* \fIusers' data\fP */ +    caddr_t     x_private;       /* \fIpointer to private data\fP */ +    caddr_t     x_base;          /* \fIprivate for position info\fP */ +    int         x_handy;         /* \fIextra private word\fP */ +} XDR; +.DE +The +.I x_op +field is the current operation being performed on the stream. +This field is important to the XDR primitives, +but should not affect a stream's implementation. +That is, a stream's implementation should not depend +on this value. +The fields +.I x_private , +.I x_base , +and +.I x_handy +are private to the particular +stream's implementation. +The field +.I x_public +is for the XDR client and should never be used by +the XDR stream implementations or the XDR primitives. +.I x_getpostn() , +.I x_setpostn() +and +.I x_destroy() +are macros for accessing operations.  The operation +.I x_inline() +takes two parameters: +an XDR *, and an unsigned integer, which is a byte count. +The routine returns a pointer to a piece of +the stream's internal buffer. +The caller can then use the buffer segment for any purpose. +From the stream's point of view, the bytes in the +buffer segment have been consumed or put. +The routine may return +.I NULL  +if it cannot return a buffer segment of the requested size. +(The +.I x_inline()  +routine is for cycle squeezers. +Use of the resulting buffer is not data-portable. +Users are encouraged not to use this feature.)  +.LP +The operations +.I x_getbytes() +and +.I x_putbytes() +blindly get and put sequences of bytes +from or to the underlying stream; +they return +.I TRUE  +if they are successful, and +.I FALSE  +otherwise.  The routines have identical parameters (replace +.I xxx ): +.DS +.ft CW +bool_t +xxxbytes(xdrs, buf, bytecount) +	XDR *xdrs; +	char *buf; +	u_int bytecount; +.DE +The operations +.I x_getlong() +and +.I x_putlong() +receive and put +long numbers from and to the data stream. +It is the responsibility of these routines +to translate the numbers between the machine representation +and the (standard) external representation. +The UNIX primitives +.I htonl() +and +.I ntohl() +can be helpful in accomplishing this. +The higher-level XDR implementation assumes that +signed and unsigned long integers contain the same number of bits, +and that nonnegative integers +have the same bit representations as unsigned integers. +The routines return +.I TRUE +if they succeed, and +.I FALSE  +otherwise.  They have identical parameters: +.DS +.ft CW +bool_t +xxxlong(xdrs, lp) +	XDR *xdrs; +	long *lp; +.DE +Implementors of new XDR streams must make an XDR structure +(with new operation routines) available to clients, +using some kind of create routine. +.NH 1 +\&Advanced Topics +.IX XDR "advanced topics" +.LP +This section describes techniques for passing data structures that +are not covered in the preceding sections.  Such structures include +linked lists (of arbitrary lengths).  Unlike the simpler examples +covered in the earlier sections, the following examples are written +using both the XDR C library routines and the XDR data description  +language.   +The +.I "External Data Representation Standard: Protocol Specification" +describes this  +language in complete detail. +.NH 2 +\&Linked Lists +.IX XDR "linked lists" +.LP +The last example in the +.I Pointers +topic earlier in this chapter  +presented a C data structure and its associated XDR +routines for a individual's gross assets and liabilities.   +The example is duplicated below: +.ie t .DS +.el .DS L +.ft CW +struct gnumbers { +	long g_assets; +	long g_liabilities; +}; +.sp.5 +bool_t +xdr_gnumbers(xdrs, gp) +	XDR *xdrs; +	struct gnumbers *gp; +{ +	if (xdr_long(xdrs, &(gp->g_assets))) +		return(xdr_long(xdrs, &(gp->g_liabilities))); +	return(FALSE); +} +.DE +.LP +Now assume that we wish to implement a linked list of such information.  +A data structure could be constructed as follows: +.ie t .DS +.el .DS L +.ft CW +struct gnumbers_node { +	struct gnumbers gn_numbers; +	struct gnumbers_node *gn_next; +}; +.sp .5 +typedef struct gnumbers_node *gnumbers_list; +.DE +.LP +The head of the linked list can be thought of as the data object; +that is, the head is not merely a convenient shorthand for a +structure.  Similarly the  +.I gn_next  +field is used to indicate whether or not the object has terminated.   +Unfortunately, if the object continues, the  +.I gn_next  +field is also the address of where it continues. The link addresses  +carry no useful information when the object is serialized. +.LP +The XDR data description of this linked list is described by the  +recursive declaration of  +.I gnumbers_list : +.ie t .DS +.el .DS L +.ft CW +struct gnumbers { +	int g_assets; +	int g_liabilities; +}; +.sp .5 +struct gnumbers_node { +	gnumbers gn_numbers; +	gnumbers_node *gn_next; +}; +.DE +.LP +In this description, the boolean indicates whether there is more data +following it. If the boolean is  +.I FALSE , +then it is the last data field of the structure. If it is  +.I TRUE , +then it is followed by a gnumbers structure and (recursively) by a  +.I gnumbers_list . +Note that the C declaration has no boolean explicitly declared in it  +(though the  +.I gn_next  +field implicitly carries the information), while the XDR data  +description has no pointer explicitly declared in it. +.LP +Hints for writing the XDR routines for a  +.I gnumbers_list  +follow easily from the XDR description above. Note how the primitive  +.I xdr_pointer()  +is used to implement the XDR union above. +.ie t .DS +.el .DS L +.ft CW +bool_t +xdr_gnumbers_node(xdrs, gn) +	XDR *xdrs; +	gnumbers_node *gn; +{ +	return(xdr_gnumbers(xdrs, &gn->gn_numbers) && +		xdr_gnumbers_list(xdrs, &gp->gn_next)); +} +.sp .5 +bool_t +xdr_gnumbers_list(xdrs, gnp) +	XDR *xdrs; +	gnumbers_list *gnp; +{ +	return(xdr_pointer(xdrs, gnp,  +		sizeof(struct gnumbers_node),  +		xdr_gnumbers_node)); +} +.DE +.LP +The unfortunate side effect of XDR'ing a list with these routines +is that the C stack grows linearly with respect to the number of +node in the list.  This is due to the recursion. The following +routine collapses the above two mutually recursive into a single, +non-recursive one. +.ie t .DS +.el .DS L +.ft CW +bool_t +xdr_gnumbers_list(xdrs, gnp) +	XDR *xdrs; +	gnumbers_list *gnp; +{ +	bool_t more_data; +	gnumbers_list *nextp; +.sp .5 +	for (;;) { +		more_data = (*gnp != NULL); +		if (!xdr_bool(xdrs, &more_data)) { +			return(FALSE); +		} +		if (! more_data) { +			break; +		} +		if (xdrs->x_op == XDR_FREE) { +			nextp = &(*gnp)->gn_next; +		} +		if (!xdr_reference(xdrs, gnp,  +			sizeof(struct gnumbers_node), xdr_gnumbers)) { + +		return(FALSE); +		} +		gnp = (xdrs->x_op == XDR_FREE) ?  +			nextp : &(*gnp)->gn_next; +	} +	*gnp = NULL; +	return(TRUE); +} +.DE +.LP +The first task is to find out whether there is more data or not, +so that this boolean information can be serialized. Notice that +this statement is unnecessary in the  +.I XDR_DECODE  +case, since the value of more_data is not known until we  +deserialize it in the next statement. +.LP +The next statement XDR's the more_data field of the XDR union.  +Then if there is truly no more data, we set this last pointer to  +.I NULL  +to indicate the end of the list, and return  +.I TRUE  +because we are done. Note that setting the pointer to  +.I NULL  +is only important in the  +.I XDR_DECODE  +case, since it is already  +.I NULL  +in the  +.I XDR_ENCODE  +and  +XDR_FREE  +cases. +.LP +Next, if the direction is  +.I XDR_FREE , +the value of  +.I nextp  +is set to indicate the location of the next pointer in the list.  +We do this now because we need to dereference gnp to find the  +location of the next item in the list, and after the next  +statement the storage pointed to by +.I gnp  +will be freed up and no be longer valid.  We can't do this for all +directions though, because in the  +.I XDR_DECODE  +direction the value of  +.I gnp  +won't be set until the next statement. +.LP +Next, we XDR the data in the node using the primitive  +.I xdr_reference (). +.I xdr_reference()  +is like  +.I xdr_pointer()  +which we used before, but it does not +send over the boolean indicating whether there is more data.  +We use it instead of  +.I xdr_pointer()  +because we have already XDR'd this information ourselves. Notice  +that the xdr routine passed is not the same type as an element  +in the list. The routine passed is  +.I xdr_gnumbers (), +for XDR'ing gnumbers, but each element in the list is actually of  +type  +.I gnumbers_node . +We don't pass  +.I xdr_gnumbers_node()  +because it is recursive, and instead use  +.I xdr_gnumbers()  +which XDR's all of the non-recursive part.  Note that this trick  +will work only if the  +.I gn_numbers  +field is the first item in each element, so that their addresses  +are identical when passed to  +.I xdr_reference (). +.LP +Finally, we update  +.I gnp  +to point to the next item in the list. If the direction is  +.I XDR_FREE , +we set it to the previously saved value, otherwise we can  +dereference  +.I gnp  +to get the proper value.  Though harder to understand than the  +recursive version, this non-recursive routine is far less likely +to blow the C stack.  It will also run more efficiently since +a lot of procedure call overhead has been removed. Most lists  +are small though (in the hundreds of items or less) and the  +recursive version should be sufficient for them. +.EQ +delim off +.EN diff --git a/lib/librpc/doc/xdr.rfc.ms b/lib/librpc/doc/xdr.rfc.ms new file mode 100644 index 000000000000..d4baff53915b --- /dev/null +++ b/lib/librpc/doc/xdr.rfc.ms @@ -0,0 +1,1058 @@ +.\" +.\"  Must use -- tbl -- with this one +.\" +.\" @(#)xdr.rfc.ms	2.2 88/08/05 4.0 RPCSRC +.de BT +.if \\n%=1 .tl ''- % -'' +.. +.ND +.\" prevent excess underlining in nroff +.if n .fp 2 R +.OH 'External Data Representation Standard''Page %' +.EH 'Page %''External Data Representation Standard' +.IX "External Data Representation" +.if \\n%=1 .bp +.SH +\&External Data Representation Standard: Protocol Specification +.IX XDR RFC +.IX XDR "protocol specification" +.LP +.NH 0 +\&Status of this Standard +.nr OF 1 +.IX XDR "RFC status" +.LP +Note: This chapter specifies a protocol that Sun Microsystems, Inc., and  +others are using.  It has been designated RFC1014 by the ARPA Network +Information Center. +.NH 1 +Introduction +\& +.LP +XDR is a standard for the description and encoding of data.  It is +useful for transferring data between different computer +architectures, and has been used to communicate data between such +diverse machines as the Sun Workstation, VAX, IBM-PC, and Cray. +XDR fits into the ISO presentation layer, and is roughly analogous in +purpose to X.409, ISO Abstract Syntax Notation.  The major difference +between these two is that XDR uses implicit typing, while X.409 uses +explicit typing. +.LP +XDR uses a language to describe data formats.  The language can only +be used only to describe data; it is not a programming language. +This language allows one to describe intricate data formats in a +concise manner. The alternative of using graphical representations +(itself an informal language) quickly becomes incomprehensible when +faced with complexity.  The XDR language itself is similar to the C +language [1], just as Courier [4] is similar to Mesa. Protocols such +as Sun RPC (Remote Procedure Call) and the NFS (Network File System) +use XDR to describe the format of their data. +.LP +The XDR standard makes the following assumption: that bytes (or +octets) are portable, where a byte is defined to be 8 bits of data. +A given hardware device should encode the bytes onto the various +media in such a way that other hardware devices may decode the bytes +without loss of meaning.  For example, the Ethernet standard +suggests that bytes be encoded in "little-endian" style [2], or least +significant bit first. +.NH 2 +\&Basic Block Size +.IX XDR "basic block size" +.IX XDR "block size" +.LP +The representation of all items requires a multiple of four bytes (or +32 bits) of data.  The bytes are numbered 0 through n-1.  The bytes +are read or written to some byte stream such that byte m always +precedes byte m+1.  If the n bytes needed to contain the data are not +a multiple of four, then the n bytes are followed by enough (0 to 3) +residual zero bytes, r, to make the total byte count a multiple of 4. +.LP +We include the familiar graphic box notation for illustration and +comparison.  In most illustrations, each box (delimited by a plus +sign at the 4 corners and vertical bars and dashes) depicts a byte. +Ellipses (...) between boxes show zero or more additional bytes where +required. +.ie t .DS +.el .DS L +\fIA Block\fP + +\f(CW+--------+--------+...+--------+--------+...+--------+ +| byte 0 | byte 1 |...|byte n-1|    0   |...|    0   | ++--------+--------+...+--------+--------+...+--------+ +|<-----------n bytes---------->|<------r bytes------>| +|<-----------n+r (where (n+r) mod 4 = 0)>----------->|\fP + +.DE +.NH 1 +\&XDR Data Types +.IX XDR "data types" +.IX "XDR data types" +.LP +Each of the sections that follow describes a data type defined in the +XDR standard, shows how it is declared in the language, and includes +a graphic illustration of its encoding. +.LP +For each data type in the language we show a general paradigm +declaration.  Note that angle brackets (< and >) denote +variable length sequences of data and square brackets ([ and ]) denote +fixed-length sequences of data.  "n", "m" and "r" denote integers. +For the full language specification and more formal definitions of +terms such as "identifier" and "declaration", refer to +.I "The XDR Language Specification" , +below. +.LP +For some data types, more specific examples are included.   +A more extensive example of a data description is in +.I "An Example of an XDR Data Description" +below. +.NH 2 +\&Integer +.IX XDR integer +.LP +An XDR signed integer is a 32-bit datum that encodes an integer in +the range [-2147483648,2147483647].  The integer is represented in +two's complement notation.  The most and least significant bytes are +0 and 3, respectively.  Integers are declared as follows: +.ie t .DS +.el .DS L +\fIInteger\fP + +\f(CW(MSB)                   (LSB) ++-------+-------+-------+-------+ +|byte 0 |byte 1 |byte 2 |byte 3 | ++-------+-------+-------+-------+ +<------------32 bits------------>\fP +.DE +.NH 2 +\&Unsigned Integer +.IX XDR "unsigned integer" +.IX XDR "integer, unsigned" +.LP +An XDR unsigned integer is a 32-bit datum that encodes a nonnegative +integer in the range [0,4294967295].  It is represented by an +unsigned binary number whose most and least significant bytes are 0 +and 3, respectively.  An unsigned integer is declared as follows: +.ie t .DS +.el .DS L +\fIUnsigned Integer\fP + +\f(CW(MSB)                   (LSB) ++-------+-------+-------+-------+ +|byte 0 |byte 1 |byte 2 |byte 3 | ++-------+-------+-------+-------+ +<------------32 bits------------>\fP +.DE +.NH 2 +\&Enumeration +.IX XDR enumeration +.LP +Enumerations have the same representation as signed integers. +Enumerations are handy for describing subsets of the integers. +Enumerated data is declared as follows: +.ft CW +.DS +enum { name-identifier = constant, ... } identifier; +.DE +For example, the three colors red, yellow, and blue could be +described by an enumerated type: +.DS +.ft CW +enum { RED = 2, YELLOW = 3, BLUE = 5 } colors; +.DE +It is an error to encode as an enum any other integer than those that +have been given assignments in the enum declaration. +.NH 2 +\&Boolean +.IX XDR boolean +.LP +Booleans are important enough and occur frequently enough to warrant +their own explicit type in the standard.  Booleans are declared as +follows: +.DS +.ft CW +bool identifier; +.DE +This is equivalent to: +.DS +.ft CW +enum { FALSE = 0, TRUE = 1 } identifier; +.DE +.NH 2 +\&Hyper Integer and Unsigned Hyper Integer +.IX XDR "hyper integer" +.IX XDR "integer, hyper" +.LP +The standard also defines 64-bit (8-byte) numbers called hyper +integer and unsigned hyper integer.  Their representations are the +obvious extensions of integer and unsigned integer defined above. +They are represented in two's complement notation.  The most and +least significant bytes are 0 and 7, respectively.  Their +declarations: +.ie t .DS +.el .DS L +\fIHyper Integer\fP +\fIUnsigned Hyper Integer\fP + +\f(CW(MSB)                                                   (LSB) ++-------+-------+-------+-------+-------+-------+-------+-------+ +|byte 0 |byte 1 |byte 2 |byte 3 |byte 4 |byte 5 |byte 6 |byte 7 | ++-------+-------+-------+-------+-------+-------+-------+-------+ +<----------------------------64 bits---------------------------->\fP +.DE +.NH 2 +\&Floating-point +.IX XDR "integer, floating point" +.IX XDR "floating-point integer" +.LP +The standard defines the floating-point data type "float" (32 bits or +4 bytes).  The encoding used is the IEEE standard for normalized +single-precision floating-point numbers [3].  The following three +fields describe the single-precision floating-point number: +.RS +.IP \fBS\fP: +The sign of the number.  Values 0 and  1 represent  positive and +negative, respectively.  One bit. +.IP \fBE\fP: +The exponent of the number, base 2.  8  bits are devoted to this +field.  The exponent is biased by 127. +.IP \fBF\fP: +The fractional part of the number's mantissa,  base 2.   23 bits +are devoted to this field. +.RE +.LP +Therefore, the floating-point number is described by: +.DS +(-1)**S * 2**(E-Bias) * 1.F +.DE +It is declared as follows: +.ie t .DS +.el .DS L +\fISingle-Precision Floating-Point\fP + +\f(CW+-------+-------+-------+-------+ +|byte 0 |byte 1 |byte 2 |byte 3 | +S|   E   |           F          | ++-------+-------+-------+-------+ +1|<- 8 ->|<-------23 bits------>| +<------------32 bits------------>\fP +.DE +Just as the most and least significant bytes of a number are 0 and 3, +the most and least significant bits of a single-precision floating- +point number are 0 and 31.  The beginning bit (and most significant +bit) offsets of S, E, and F are 0, 1, and 9, respectively.  Note that +these numbers refer to the mathematical positions of the bits, and +NOT to their actual physical locations (which vary from medium to +medium). +.LP +The IEEE specifications should be consulted concerning the encoding +for signed zero, signed infinity (overflow), and denormalized numbers +(underflow) [3].  According to IEEE specifications, the "NaN" (not a +number) is system dependent and should not be used externally. +.NH 2 +\&Double-precision Floating-point +.IX XDR "integer, double-precision floating point" +.IX XDR "double-precision floating-point integer" +.LP +The standard defines the encoding for the double-precision floating- +point data type "double" (64 bits or 8 bytes).  The encoding used is +the IEEE standard for normalized double-precision floating-point +numbers [3].  The standard encodes the following three fields, which +describe the double-precision floating-point number: +.RS +.IP \fBS\fP: +The sign of the number.  Values  0 and 1  represent positive and +negative, respectively.  One bit. +.IP \fBE\fP: +The exponent of the number, base 2.  11 bits are devoted to this +field.  The exponent is biased by 1023. +.IP \fBF\fP: +The fractional part of the number's  mantissa, base 2.   52 bits +are devoted to this field. +.RE +.LP +Therefore, the floating-point number is described by: +.DS +(-1)**S * 2**(E-Bias) * 1.F +.DE +It is declared as follows: +.ie t .DS +.el .DS L +\fIDouble-Precision Floating-Point\fP + +\f(CW+------+------+------+------+------+------+------+------+ +|byte 0|byte 1|byte 2|byte 3|byte 4|byte 5|byte 6|byte 7| +S|    E   |                    F                        | ++------+------+------+------+------+------+------+------+ +1|<--11-->|<-----------------52 bits------------------->| +<-----------------------64 bits------------------------->\fP +.DE +Just as the most and least significant bytes of a number are 0 and 3, +the most and least significant bits of a double-precision floating- +point number are 0 and 63.  The beginning bit (and most significant +bit) offsets of S, E , and F are 0, 1, and 12, respectively.  Note +that these numbers refer to the mathematical positions of the bits, +and NOT to their actual physical locations (which vary from medium to +medium). +.LP +The IEEE specifications should be consulted concerning the encoding +for signed zero, signed infinity (overflow), and denormalized numbers +(underflow) [3].  According to IEEE specifications, the "NaN" (not a +number) is system dependent and should not be used externally. +.NH 2 +\&Fixed-length Opaque Data +.IX XDR "fixed-length opaque data" +.IX XDR "opaque data, fixed length" +.LP +At times, fixed-length uninterpreted data needs to be passed among +machines.  This data is called "opaque" and is declared as follows: +.DS +.ft CW +opaque identifier[n]; +.DE +where the constant n is the (static) number of bytes necessary to +contain the opaque data.  If n is not a multiple of four, then the n +bytes are followed by enough (0 to 3) residual zero bytes, r, to make +the total byte count of the opaque object a multiple of four. +.ie t .DS +.el .DS L +\fIFixed-Length Opaque\fP + +\f(CW0        1     ... ++--------+--------+...+--------+--------+...+--------+ +| byte 0 | byte 1 |...|byte n-1|    0   |...|    0   | ++--------+--------+...+--------+--------+...+--------+ +|<-----------n bytes---------->|<------r bytes------>| +|<-----------n+r (where (n+r) mod 4 = 0)------------>|\fP +.DE +.NH 2 +\&Variable-length Opaque Data +.IX XDR "variable-length opaque data" +.IX XDR "opaque data, variable length" +.LP +The standard also provides for variable-length (counted) opaque data, +defined as a sequence of n (numbered 0 through n-1) arbitrary bytes +to be the number n encoded as an unsigned integer (as described +below), and followed by the n bytes of the sequence. +.LP +Byte m of the sequence always precedes byte m+1 of the sequence, and +byte 0 of the sequence always follows the sequence's length (count). +enough (0 to 3) residual zero bytes, r, to make the total byte count +a multiple of four.  Variable-length opaque data is declared in the +following way: +.DS +.ft CW +opaque identifier<m>; +.DE +or +.DS +.ft CW +opaque identifier<>; +.DE +The constant m denotes an upper bound of the number of bytes that the +sequence may contain.  If m is not specified, as in the second +declaration, it is assumed to be (2**32) - 1, the maximum length. +The constant m would normally be found in a protocol specification. +For example, a filing protocol may state that the maximum data +transfer size is 8192 bytes, as follows: +.DS +.ft CW +opaque filedata<8192>; +.DE +This can be illustrated as follows: +.ie t .DS +.el .DS L +\fIVariable-Length Opaque\fP + +\f(CW0     1     2     3     4     5   ... ++-----+-----+-----+-----+-----+-----+...+-----+-----+...+-----+ +|        length n       |byte0|byte1|...| n-1 |  0  |...|  0  | ++-----+-----+-----+-----+-----+-----+...+-----+-----+...+-----+ +|<-------4 bytes------->|<------n bytes------>|<---r bytes--->| +|<----n+r (where (n+r) mod 4 = 0)---->|\fP +.DE +.LP +It   is  an error  to  encode  a  length  greater  than the maximum +described in the specification. +.NH 2 +\&String +.IX XDR string +.LP +The standard defines a string of n (numbered 0 through n-1) ASCII +bytes to be the number n encoded as an unsigned integer (as described +above), and followed by the n bytes of the string.  Byte m of the +string always precedes byte m+1 of the string, and byte 0 of the +string always follows the string's length.  If n is not a multiple of +four, then the n bytes are followed by enough (0 to 3) residual zero +bytes, r, to make the total byte count a multiple of four.  Counted +byte strings are declared as follows: +.DS +.ft CW +string object<m>; +.DE +or +.DS +.ft CW +string object<>; +.DE +The constant m denotes an upper bound of the number of bytes that a +string may contain.  If m is not specified, as in the second +declaration, it is assumed to be (2**32) - 1, the maximum length. +The constant m would normally be found in a protocol specification. +For example, a filing protocol may state that a file name can be no +longer than 255 bytes, as follows: +.DS +.ft CW +string filename<255>; +.DE +Which can be illustrated as: +.ie t .DS +.el .DS L +\fIA String\fP + +\f(CW0     1     2     3     4     5   ... ++-----+-----+-----+-----+-----+-----+...+-----+-----+...+-----+ +|        length n       |byte0|byte1|...| n-1 |  0  |...|  0  | ++-----+-----+-----+-----+-----+-----+...+-----+-----+...+-----+ +|<-------4 bytes------->|<------n bytes------>|<---r bytes--->| +|<----n+r (where (n+r) mod 4 = 0)---->|\fP +.DE +.LP +It   is an  error  to  encode  a length greater  than   the maximum +described in the specification. +.NH 2 +\&Fixed-length Array +.IX XDR "fixed-length array" +.IX XDR "array, fixed length" +.LP +Declarations for fixed-length arrays of homogeneous elements are in +the following form: +.DS +.ft CW +type-name identifier[n]; +.DE +Fixed-length arrays of elements numbered 0 through n-1 are encoded by +individually encoding the elements of the array in their natural +order, 0 through n-1.  Each element's size is a multiple of four +bytes. Though all elements are of the same type, the elements may +have different sizes.  For example, in a fixed-length array of +strings, all elements are of type "string", yet each element will +vary in its length. +.ie t .DS +.el .DS L +\fIFixed-Length Array\fP + +\f(CW+---+---+---+---+---+---+---+---+...+---+---+---+---+ +|   element 0   |   element 1   |...|  element n-1  | ++---+---+---+---+---+---+---+---+...+---+---+---+---+ +|<--------------------n elements------------------->|\fP +.DE +.NH 2 +\&Variable-length Array +.IX XDR "variable-length array" +.IX XDR "array, variable length" +.LP +Counted arrays provide the ability to encode variable-length arrays +of homogeneous elements.  The array is encoded as the element count n +(an unsigned integer) followed by the encoding of each of the array's +elements, starting with element 0 and progressing through element n- +1.  The declaration for variable-length arrays follows this form: +.DS +.ft CW +type-name identifier<m>; +.DE +or +.DS +.ft CW +type-name identifier<>; +.DE +The constant m specifies the maximum acceptable element count of an +array; if  m is not specified, as  in the second declaration, it is +assumed to be (2**32) - 1. +.ie t .DS +.el .DS L +\fICounted Array\fP + +\f(CW0  1  2  3 ++--+--+--+--+--+--+--+--+--+--+--+--+...+--+--+--+--+ +|     n     | element 0 | element 1 |...|element n-1| ++--+--+--+--+--+--+--+--+--+--+--+--+...+--+--+--+--+ +|<-4 bytes->|<--------------n elements------------->|\fP +.DE +It is  an error to  encode  a  value of n that  is greater than the +maximum described in the specification. +.NH 2 +\&Structure +.IX XDR structure +.LP +Structures are declared as follows: +.DS +.ft CW +struct { +	component-declaration-A; +	component-declaration-B; +	\&... +} identifier; +.DE +The components of the structure are encoded in the order of their +declaration in the structure.  Each component's size is a multiple of +four bytes, though the components may be different sizes. +.ie t .DS +.el .DS L +\fIStructure\fP + +\f(CW+-------------+-------------+... +| component A | component B |... ++-------------+-------------+...\fP +.DE +.NH 2 +\&Discriminated Union +.IX XDR "discriminated union" +.IX XDR union discriminated +.LP +A discriminated union is a type composed of a discriminant followed +by a type selected from a set of prearranged types according to the +value of the discriminant.  The type of discriminant is either "int", +"unsigned int", or an enumerated type, such as "bool".  The component +types are called "arms" of the union, and are preceded by the value +of the discriminant which implies their encoding.  Discriminated +unions are declared as follows: +.DS +.ft CW +union switch (discriminant-declaration) { +	case discriminant-value-A: +	arm-declaration-A; +	case discriminant-value-B: +	arm-declaration-B; +	\&... +	default: default-declaration; +} identifier; +.DE +Each "case" keyword is followed by a legal value of the discriminant. +The default arm is optional.  If it is not specified, then a valid +encoding of the union cannot take on unspecified discriminant values. +The size of the implied arm is always a multiple of four bytes. +.LP +The discriminated union is encoded as its discriminant followed by +the encoding of the implied arm. +.ie t .DS +.el .DS L +\fIDiscriminated Union\fP + +\f(CW0   1   2   3 ++---+---+---+---+---+---+---+---+ +|  discriminant |  implied arm  | ++---+---+---+---+---+---+---+---+ +|<---4 bytes--->|\fP +.DE +.NH 2 +\&Void +.IX XDR void +.LP +An XDR void is a 0-byte quantity.  Voids are useful for describing +operations that take no data as input or no data as output. They are +also useful in unions, where some arms may contain data and others do +not.  The declaration is simply as follows: +.DS +.ft CW +void; +.DE +Voids are illustrated as follows: +.ie t .DS +.el .DS L +\fIVoid\fP + +\f(CW  ++ +  || +  ++ +--><-- 0 bytes\fP +.DE +.NH 2 +\&Constant +.IX XDR constant +.LP +The data declaration for a constant follows this form: +.DS +.ft CW +const name-identifier = n; +.DE +"const" is used to define a symbolic name for a constant; it does not +declare any data.  The symbolic constant may be used anywhere a +regular constant may be used.  For example, the following defines a +symbolic constant DOZEN, equal to 12. +.DS +.ft CW +const DOZEN = 12; +.DE +.NH 2 +\&Typedef +.IX XDR typedef +.LP +"typedef" does not declare any data either, but serves to define new +identifiers for declaring data. The syntax is: +.DS +.ft CW +typedef declaration; +.DE +The new type name is actually the variable name in the declaration +part of the typedef.  For example, the following defines a new type +called "eggbox" using an existing type called "egg": +.DS +.ft CW +typedef egg eggbox[DOZEN]; +.DE +Variables declared using the new type name have the same type as the +new type name would have in the typedef, if it was considered a +variable.  For example, the following two declarations are equivalent +in declaring the variable "fresheggs": +.DS +.ft CW +eggbox  fresheggs; +egg     fresheggs[DOZEN]; +.DE +When a typedef involves a struct, enum, or union definition, there is +another (preferred) syntax that may be used to define the same type. +In general, a typedef of the following form: +.DS +.ft CW +typedef <<struct, union, or enum definition>> identifier; +.DE +may be converted to the alternative form by removing the "typedef" +part and placing the identifier after the "struct", "union", or +"enum" keyword, instead of at the end.  For example, here are the two +ways to define the type "bool": +.DS +.ft CW +typedef enum {    /* \fIusing typedef\fP */ +	FALSE = 0, +	TRUE = 1 +	} bool; + +enum bool {       /* \fIpreferred alternative\fP */ +	FALSE = 0, +	TRUE = 1 +	}; +.DE +The reason this syntax is preferred is one does not have to wait +until the end of a declaration to figure out the name of the new +type. +.NH 2 +\&Optional-data +.IX XDR "optional data" +.IX XDR "data, optional" +.LP +Optional-data is one kind of union that occurs so frequently that we +give it a special syntax of its own for declaring it.  It is declared +as follows: +.DS +.ft CW +type-name *identifier; +.DE +This is equivalent to the following union: +.DS +.ft CW +union switch (bool opted) { +	case TRUE: +	type-name element; +	case FALSE: +	void; +} identifier; +.DE +It is also equivalent to the following variable-length array +declaration, since the boolean "opted" can be interpreted as the +length of the array: +.DS +.ft CW +type-name identifier<1>; +.DE +Optional-data is not so interesting in itself, but it is very useful +for describing recursive data-structures such as linked-lists and +trees.  For example, the following defines a type "stringlist" that +encodes lists of arbitrary length strings: +.DS +.ft CW +struct *stringlist { +	string item<>; +	stringlist next; +}; +.DE +It could have been equivalently declared as the following union: +.DS +.ft CW +union stringlist switch (bool opted) { +	case TRUE: +		struct { +			string item<>; +			stringlist next; +		} element; +	case FALSE: +		void; +}; +.DE +or as a variable-length array: +.DS +.ft CW +struct stringlist<1> { +	string item<>; +	stringlist next; +}; +.DE +Both of these declarations obscure the intention of the stringlist +type, so the optional-data declaration is preferred over both of +them.  The optional-data type also has a close correlation to how +recursive data structures are represented in high-level languages +such as Pascal or C by use of pointers. In fact, the syntax is the +same as that of the C language for pointers. +.NH 2 +\&Areas for Future Enhancement +.IX XDR futures +.LP +The XDR standard lacks representations for bit fields and bitmaps, +since the standard is based on bytes.  Also missing are packed (or +binary-coded) decimals. +.LP +The intent of the XDR standard was not to describe every kind of data +that people have ever sent or will ever want to send from machine to +machine. Rather, it only describes the most commonly used data-types +of high-level languages such as Pascal or C so that applications +written in these languages will be able to communicate easily over +some medium. +.LP +One could imagine extensions to XDR that would let it describe almost +any existing protocol, such as TCP.  The minimum necessary for this +are support for different block sizes and byte-orders.  The XDR +discussed here could then be considered the 4-byte big-endian member +of a larger XDR family. +.NH 1 +\&Discussion +.sp 2 +.NH 2 +\&Why a Language for Describing Data? +.IX XDR language +.LP +There are many advantages in using a data-description language such +as  XDR  versus using  diagrams.   Languages are  more  formal than +diagrams   and   lead  to less  ambiguous   descriptions  of  data. +Languages are also easier  to understand and allow  one to think of +other   issues instead of  the   low-level details of bit-encoding. +Also,  there is  a close analogy  between the  types  of XDR and  a +high-level language   such  as C   or    Pascal.   This makes   the +implementation of XDR encoding and decoding modules an easier task. +Finally, the language specification itself  is an ASCII string that +can be passed from  machine to machine  to perform  on-the-fly data +interpretation. +.NH 2 +\&Why Only one Byte-Order for an XDR Unit? +.IX XDR "byte order" +.LP +Supporting two byte-orderings requires a higher level protocol for +determining in which byte-order the data is encoded.  Since XDR is +not a protocol, this can't be done.  The advantage of this, though, +is that data in XDR format can be written to a magnetic tape, for +example, and any machine will be able to interpret it, since no +higher level protocol is necessary for determining the byte-order. +.NH 2 +\&Why does XDR use Big-Endian Byte-Order? +.LP +Yes, it is unfair, but having only one byte-order means you have to +be unfair to somebody.  Many architectures, such as the Motorola +68000 and IBM 370, support the big-endian byte-order. +.NH 2 +\&Why is the XDR Unit Four Bytes Wide? +.LP +There is a tradeoff in choosing the XDR unit size.  Choosing a small +size such as two makes the encoded data small, but causes alignment +problems for machines that aren't aligned on these boundaries.  A +large size such as eight means the data will be aligned on virtually +every machine, but causes the encoded data to grow too big.  We chose +four as a compromise.  Four is big enough to support most +architectures efficiently, except for rare machines such as the +eight-byte aligned Cray.  Four is also small enough to keep the +encoded data restricted to a reasonable size. +.NH 2 +\&Why must Variable-Length Data be Padded with Zeros? +.IX XDR "variable-length data" +.LP +It is desirable that the same data encode into the same thing on all +machines, so that encoded data can be meaningfully compared or +checksummed.  Forcing the padded bytes to be zero ensures this. +.NH 2 +\&Why is there No Explicit Data-Typing? +.LP +Data-typing has a relatively high cost for what small advantages it +may have.  One cost is the expansion of data due to the inserted type +fields.  Another is the added cost of interpreting these type fields +and acting accordingly.  And most protocols already know what type +they expect, so data-typing supplies only redundant information. +However, one can still get the benefits of data-typing using XDR. One +way is to encode two things: first a string which is the XDR data +description of the encoded data, and then the encoded data itself. +Another way is to assign a value to all the types in XDR, and then +define a universal type which takes this value as its discriminant +and for each value, describes the corresponding data type. +.NH 1 +\&The XDR Language Specification +.IX XDR language +.sp 1 +.NH 2 +\&Notational Conventions +.IX "XDR language" notation +.LP +This specification  uses an extended Backus-Naur Form  notation for +describing the XDR language.   Here is  a brief description  of the +notation: +.IP  1. +The characters +.I | , +.I ( , +.I ) , +.I [ , +.I ] , +.I " , +and +.I *  +are special. +.IP  2. +Terminal symbols are  strings of any  characters surrounded by +double quotes. +.IP  3. +Non-terminal symbols are strings of non-special characters. +.IP  4. +Alternative items are separated by a vertical bar ("\fI|\fP"). +.IP  5. +Optional items are enclosed in brackets. +.IP  6. +Items are grouped together by enclosing them in parentheses. +.IP  7. +A +.I *  +following an item means  0 or more  occurrences of that item. +.LP +For example,  consider  the  following pattern: +.DS L +"a " "very" (", " " very")* [" cold " "and"]  " rainy " ("day" | "night") +.DE +.LP +An infinite  number of  strings match  this pattern. A few  of them +are: +.DS +"a very rainy day" +"a very, very rainy day" +"a very cold and  rainy day" +"a very, very, very cold and  rainy night" +.DE +.NH 2 +\&Lexical Notes +.IP  1. +Comments begin with '/*' and terminate with '*/'. +.IP  2. +White space serves to separate items and is otherwise ignored. +.IP  3. +An identifier is a letter followed by  an optional sequence of +letters, digits or underbar ('_').  The case of identifiers is +not ignored. +.IP  4. +A  constant is  a  sequence  of  one  or  more decimal digits, +optionally preceded by a minus-sign ('-'). +.NH 2 +\&Syntax Information +.IX "XDR language" syntax +.DS +.ft CW +declaration: +	type-specifier identifier +	| type-specifier identifier "[" value "]" +	| type-specifier identifier "<" [ value ] ">" +	| "opaque" identifier "[" value "]" +	| "opaque" identifier "<" [ value ] ">" +	| "string" identifier "<" [ value ] ">" +	| type-specifier "*" identifier +	| "void" +.DE +.DS +.ft CW +value: +	constant +	| identifier + +type-specifier: +	  [ "unsigned" ] "int" +	| [ "unsigned" ] "hyper" +	| "float" +	| "double" +	| "bool" +	| enum-type-spec +	| struct-type-spec +	| union-type-spec +	| identifier +.DE +.DS +.ft CW +enum-type-spec: +	"enum" enum-body + +enum-body: +	"{" +	( identifier "=" value ) +	( "," identifier "=" value )* +	"}" +.DE +.DS +.ft CW +struct-type-spec: +	"struct" struct-body + +struct-body: +	"{" +	( declaration ";" ) +	( declaration ";" )* +	"}" +.DE +.DS +.ft CW +union-type-spec: +	"union" union-body + +union-body: +	"switch" "(" declaration ")" "{" +	( "case" value ":" declaration ";" ) +	( "case" value ":" declaration ";" )* +	[ "default" ":" declaration ";" ] +	"}" + +constant-def: +	"const" identifier "=" constant ";" +.DE +.DS +.ft CW +type-def: +	"typedef" declaration ";" +	| "enum" identifier enum-body ";" +	| "struct" identifier struct-body ";" +	| "union" identifier union-body ";" + +definition: +	type-def +	| constant-def + +specification: +	definition * +.DE +.NH 3 +\&Syntax Notes +.IX "XDR language" syntax +.LP +.IP  1. +The following are keywords and cannot be used as identifiers: +"bool", "case", "const", "default", "double", "enum", "float", +"hyper", "opaque", "string", "struct", "switch", "typedef", "union", +"unsigned" and "void". +.IP  2. +Only unsigned constants may be used as size specifications for +arrays.  If an identifier is used, it must have been declared +previously as an unsigned constant in a "const" definition. +.IP  3. +Constant and type identifiers within the scope of a specification +are in the same name space and must be declared uniquely within this +scope. +.IP  4. +Similarly, variable names must  be unique within  the scope  of +struct and union declarations. Nested struct and union declarations +create new scopes. +.IP  5. +The discriminant of a union must be of a type that evaluates to +an integer. That is, "int", "unsigned int", "bool", an enumerated +type or any typedefed type that evaluates to one of these is legal. +Also, the case values must be one of the legal values of the +discriminant.  Finally, a case value may not be specified more than +once within the scope of a union declaration. +.NH 1 +\&An Example of an XDR Data Description +.LP +Here is a short XDR data description of a thing called a "file", +which might be used to transfer files from one machine to another. +.ie t .DS +.el .DS L +.ft CW + +const MAXUSERNAME = 32;     /*\fI max length of a user name \fP*/ +const MAXFILELEN = 65535;   /*\fI max length of a file      \fP*/ +const MAXNAMELEN = 255;     /*\fI max length of a file name \fP*/ + +.ft I +/* + * Types of files: + */ +.ft CW + +enum filekind { +	TEXT = 0,       /*\fI ascii data \fP*/ +	DATA = 1,       /*\fI raw data   \fP*/ +	EXEC = 2        /*\fI executable \fP*/ +}; + +.ft I +/* + * File information, per kind of file: + */ +.ft CW + +union filetype switch (filekind kind) { +	case TEXT: +		void;                           /*\fI no extra information \fP*/ +	case DATA: +		string creator<MAXNAMELEN>;     /*\fI data creator         \fP*/ +	case EXEC: +		string interpretor<MAXNAMELEN>; /*\fI program interpretor  \fP*/ +}; + +.ft I +/* + * A complete file: + */ +.ft CW + +struct file { +	string filename<MAXNAMELEN>; /*\fI name of file \fP*/ +	filetype type;               /*\fI info about file \fP*/ +	string owner<MAXUSERNAME>;   /*\fI owner of file   \fP*/ +	opaque data<MAXFILELEN>;     /*\fI file data       \fP*/ +}; +.DE +.LP +Suppose now that there is  a user named  "john" who wants to  store +his lisp program "sillyprog" that contains just  the data "(quit)". +His file would be encoded as follows: +.TS +box tab (&) ; +lfI lfI lfI lfI +rfL rfL rfL l . +Offset&Hex Bytes&ASCII&Description +_ +0&00 00 00 09&....&Length of filename = 9 +4&73 69 6c 6c&sill&Filename characters +8&79 70 72 6f&ypro& ... and more characters ... +12&67 00 00 00&g...& ... and 3 zero-bytes of fill +16&00 00 00 02&....&Filekind is EXEC = 2 +20&00 00 00 04&....&Length of interpretor = 4 +24&6c 69 73 70&lisp&Interpretor characters +28&00 00 00 04&....&Length of owner = 4 +32&6a 6f 68 6e&john&Owner characters +36&00 00 00 06&....&Length of file data = 6 +40&28 71 75 69&(qui&File data bytes ... +44&74 29 00 00&t)..& ... and 2 zero-bytes of fill +.TE +.NH 1 +\&References +.LP +[1]  Brian W. Kernighan & Dennis M. Ritchie, "The C Programming +Language", Bell Laboratories, Murray Hill, New Jersey, 1978. +.LP +[2]  Danny Cohen, "On Holy Wars and a Plea for Peace", IEEE Computer, +October 1981. +.LP +[3]  "IEEE Standard for Binary Floating-Point Arithmetic", ANSI/IEEE +Standard 754-1985, Institute of Electrical and Electronics +Engineers, August 1985. +.LP +[4]  "Courier: The Remote Procedure Call Protocol", XEROX +Corporation, XSIS 038112, December 1981. diff --git a/lib/librpc/etc/Makefile b/lib/librpc/etc/Makefile new file mode 100644 index 000000000000..beb2ce9bf903 --- /dev/null +++ b/lib/librpc/etc/Makefile @@ -0,0 +1,74 @@ +# +# @(#)Makefile	2.1 88/08/01 4.0 RPCSRC +# +#   Files and programs for /etc.  rpclib must have already been installed. +# +DESTDIR= +CFLAGS=	-O +LIB = -lrpclib +LDFLAGS= $(LIB) + +BIN = portmap rpcinfo +MISC= rpc + +all:	${BIN} + +portmap: +	${CC} ${CFLAGS} -o $@ $@.c ${LDFLAGS} + +rpcinfo:	getopt.o +	${CC} ${CFLAGS} -o $@ $@.c getopt.o ${LDFLAGS} + +install: ${BIN} +	-mkdir ${DESTDIR}/etc && chown bin ${DESTDIR}/etc && \ +		chmod 755 ${DESTDIR}/etc +	@echo "Installing RPC utility files in ${DESTDIR}/etc" +	@set -x;for i in ${BIN}; do \ +		(install -s $$i ${DESTDIR}/etc/$$i); done +	@echo "Installing ${DESTDIR}/etc/rpc" +	@set -x;for i in ${MISC}; do \ +		(install -c -m 644 $$i ${DESTDIR}/etc/$$i); done + +clean: +	rm -f core *.o +	rm -f ${BIN} + +depend: ${BIN} +	rm -f makedep +	for i in ${BIN}; do \ +	    ${CC} -M ${INCPATH} $$i.c | sed 's/\.o//' | \ +	    awk ' { if ($$1 != prev) { print rec; rec = $$0; prev = $$1; } \ +		else { if (length(rec $$2) > 78) { print rec; rec = $$0; } \ +		else rec = rec " " $$2 } } \ +		END { print rec } ' >> makedep; done +	echo '/^# DO NOT DELETE THIS LINE/+2,$$d' >eddep +	echo '$$r makedep' >>eddep +	echo 'w' >>eddep +	cp Makefile Makefile.bak +	ed - Makefile < eddep +	rm eddep makedep +	echo '# DEPENDENCIES MUST END AT END OF FILE' >> Makefile +	echo '# IF YOU PUT STUFF HERE IT WILL GO AWAY' >> Makefile +	echo '# see make depend above' >> Makefile + + +depend.42BSD depend.42bsd: +	cp /dev/null x.c +	for i in $(BIN) ; do \ +              (/bin/grep '^#[         ]*include' x.c $$i.c | sed \ +                      -e 's,<\(.*\)>,"/usr/include/\1",' \ +                      -e 's/:[^"]*"\([^"]*\)".*/: \1/' \ +	                  -e 's/\.c/\.o/' >>makedep); done +	echo '/^# DO NOT DELETE THIS LINE/+2,$$d' >eddep +	echo '$$r makedep' >>eddep +	echo 'w' >>eddep +	cp Makefile Makefile.bak +	ed - Makefile < eddep +	rm eddep makedep x.c +	echo '# DEPENDENCIES MUST END AT END OF FILE' >> Makefile +	echo '# IF YOU PUT STUFF HERE IT WILL GO AWAY' >> Makefile +	echo '# see make depend above' >> Makefile + +# DO NOT DELETE THIS LINE -- make depend uses it + + diff --git a/lib/librpc/etc/getopt.c b/lib/librpc/etc/getopt.c new file mode 100644 index 000000000000..7296b05af2e7 --- /dev/null +++ b/lib/librpc/etc/getopt.c @@ -0,0 +1,75 @@ +/* @(#)getopt.c	2.1 88/08/01 4.0 RPCSRC */ + +/* this is a public domain version of getopt */ + +/*LINTLIBRARY*/ +#ifndef NULL +#define NULL	0 +#endif NULL +#ifndef EOF +#define EOF	(-1) +#endif EOF + +#define ERR(s, c)	if(opterr){\ +	extern int strlen(), write();\ +	char errbuf[2];\ +	errbuf[0] = c; errbuf[1] = '\n';\ +	(void) write(2, argv[0], strlen(argv[0]));\ +	(void) write(2, s, strlen(s));\ +	(void) write(2, errbuf, 2);} + +#define strchr index + +extern int strcmp(); +extern char *strchr(); + +int	opterr = 1; +int	optind = 1; +int	optopt; +char	*optarg; + +int +getopt(argc, argv, opts) +int	argc; +char	**argv, *opts; +{ +	static int sp = 1; +	register int c; +	register char *cp; + +	if(sp == 1) +		if(optind >= argc || +		   argv[optind][0] != '-' || argv[optind][1] == '\0') +			return(EOF); +		else if(strcmp(argv[optind], "--") == NULL) { +			optind++; +			return(EOF); +		} +	optopt = c = argv[optind][sp]; +	if(c == ':' || (cp=strchr(opts, c)) == NULL) { +		ERR(": unknown option, -", c); +		if(argv[optind][++sp] == '\0') { +			optind++; +			sp = 1; +		} +		return('?'); +	} +	if(*++cp == ':') { +		if(argv[optind][sp+1] != '\0') +			optarg = &argv[optind++][sp+1]; +		else if(++optind >= argc) { +			ERR(": argument missing for -", c); +			sp = 1; +			return('?'); +		} else +			optarg = argv[optind++]; +		sp = 1; +	} else { +		if(argv[optind][++sp] == '\0') { +			sp = 1; +			optind++; +		} +		optarg = NULL; +	} +	return(c); +} diff --git a/lib/librpc/etc/portmap.c b/lib/librpc/etc/portmap.c new file mode 100644 index 000000000000..adfdef955ecd --- /dev/null +++ b/lib/librpc/etc/portmap.c @@ -0,0 +1,481 @@ +/* @(#)portmap.c	2.3 88/08/11 4.0 RPCSRC */ +#ifndef lint +static	char sccsid[] = "@(#)portmap.c 1.32 87/08/06 Copyr 1984 Sun Micro"; +#endif + +/* + * Copyright (c) 1984 by Sun Microsystems, Inc. + */ + +/* + * portmap.c, Implements the program,version to port number mapping for + * rpc. + */ + +/* + * Sun RPC is a product of Sun Microsystems, Inc. and is provided for + * unrestricted use provided that this legend is included on all tape + * media and as a part of the software program in whole or part.  Users + * may copy or modify Sun RPC without charge, but are not authorized + * to license or distribute it to anyone else except as part of a product or + * program developed by the user. + *  + * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE + * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR + * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. + *  + * Sun RPC is provided with no support and without any obligation on the + * part of Sun Microsystems, Inc. to assist in its use, correction, + * modification or enhancement. + *  + * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE + * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC + * OR ANY PART THEREOF. + *  + * In no event will Sun Microsystems, Inc. be liable for any lost revenue + * or profits or other special, indirect and consequential damages, even if + * Sun has been advised of the possibility of such damages. + *  + * Sun Microsystems, Inc. + * 2550 Garcia Avenue + * Mountain View, California  94043 + */ + +#include <rpc/rpc.h> +#include <rpc/pmap_prot.h> +#include <stdio.h> +#include <netdb.h> +#include <sys/socket.h> +#include <sys/ioctl.h> +#include <sys/wait.h> +#include <sys/signal.h> + +char *malloc(); +int reg_service(); +void reap(); +struct pmaplist *pmaplist; +static int debugging = 0; + +main() +{ +	SVCXPRT *xprt; +	int sock, pid, t; +	struct sockaddr_in addr; +	int len = sizeof(struct sockaddr_in); +	register struct pmaplist *pml; + +#ifndef DEBUG +	pid = fork(); +	if (pid < 0) { +		perror("portmap: fork"); +		exit(1); +	} +	if (pid != 0) +		exit(0); +	for (t = 0; t < 20; t++) +		close(t); + 	open("/", 0); + 	dup2(0, 1); + 	dup2(0, 2); + 	t = open("/dev/tty", 2); + 	if (t >= 0) { + 		ioctl(t, TIOCNOTTY, (char *)0); + 		close(t); + 	} +#endif +	if ((sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) { +		perror("portmap cannot create socket"); +		exit(1); +	} + +	addr.sin_addr.s_addr = 0; +	addr.sin_family = AF_INET; +	addr.sin_port = htons(PMAPPORT); +	if (bind(sock, (struct sockaddr *)&addr, len) != 0) { +		perror("portmap cannot bind"); +		exit(1); +	} + +	if ((xprt = svcudp_create(sock)) == (SVCXPRT *)NULL) { +		fprintf(stderr, "couldn't do udp_create\n"); +		exit(1); +	} +	/* make an entry for ourself */ +	pml = (struct pmaplist *)malloc((u_int)sizeof(struct pmaplist)); +	pml->pml_next = 0; +	pml->pml_map.pm_prog = PMAPPROG; +	pml->pml_map.pm_vers = PMAPVERS; +	pml->pml_map.pm_prot = IPPROTO_UDP; +	pml->pml_map.pm_port = PMAPPORT; +	pmaplist = pml; + +	if ((sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) { +		perror("portmap cannot create socket"); +		exit(1); +	} +	if (bind(sock, (struct sockaddr *)&addr, len) != 0) { +		perror("portmap cannot bind"); +		exit(1); +	} +	if ((xprt = svctcp_create(sock, RPCSMALLMSGSIZE, RPCSMALLMSGSIZE)) +	    == (SVCXPRT *)NULL) { +		fprintf(stderr, "couldn't do tcp_create\n"); +		exit(1); +	} +	/* make an entry for ourself */ +	pml = (struct pmaplist *)malloc((u_int)sizeof(struct pmaplist)); +	pml->pml_map.pm_prog = PMAPPROG; +	pml->pml_map.pm_vers = PMAPVERS; +	pml->pml_map.pm_prot = IPPROTO_TCP; +	pml->pml_map.pm_port = PMAPPORT; +	pml->pml_next = pmaplist; +	pmaplist = pml; + +	(void)svc_register(xprt, PMAPPROG, PMAPVERS, reg_service, FALSE); + +	(void)signal(SIGCHLD, reap); +	svc_run(); +	fprintf(stderr, "run_svc returned unexpectedly\n"); +	abort(); +} + +static struct pmaplist * +find_service(prog, vers, prot) +	u_long prog; +	u_long vers; +{ +	register struct pmaplist *hit = NULL; +	register struct pmaplist *pml; + +	for (pml = pmaplist; pml != NULL; pml = pml->pml_next) { +		if ((pml->pml_map.pm_prog != prog) || +			(pml->pml_map.pm_prot != prot)) +			continue; +		hit = pml; +		if (pml->pml_map.pm_vers == vers) +		    break; +	} +	return (hit); +} + +/*  + * 1 OK, 0 not + */ +reg_service(rqstp, xprt) +	struct svc_req *rqstp; +	SVCXPRT *xprt; +{ +	struct pmap reg; +	struct pmaplist *pml, *prevpml, *fnd; +	int ans, port; +	caddr_t t; +	 +#ifdef DEBUG +	fprintf(stderr, "server: about do a switch\n"); +#endif +	switch (rqstp->rq_proc) { + +	case PMAPPROC_NULL: +		/* +		 * Null proc call +		 */ +		if ((!svc_sendreply(xprt, xdr_void, NULL)) && debugging) { +			abort(); +		} +		break; + +	case PMAPPROC_SET: +		/* +		 * Set a program,version to port mapping +		 */ +		if (!svc_getargs(xprt, xdr_pmap, ®)) +			svcerr_decode(xprt); +		else { +			/* +			 * check to see if already used +			 * find_service returns a hit even if +			 * the versions don't match, so check for it +			 */ +			fnd = find_service(reg.pm_prog, reg.pm_vers, reg.pm_prot); +			if (fnd && fnd->pml_map.pm_vers == reg.pm_vers) { +				if (fnd->pml_map.pm_port == reg.pm_port) { +					ans = 1; +					goto done; +				} +				else { +					ans = 0; +					goto done; +				} +			} else { +				/*  +				 * add to END of list +				 */ +				pml = (struct pmaplist *) +				    malloc((u_int)sizeof(struct pmaplist)); +				pml->pml_map = reg; +				pml->pml_next = 0; +				if (pmaplist == 0) { +					pmaplist = pml; +				} else { +					for (fnd= pmaplist; fnd->pml_next != 0; +					    fnd = fnd->pml_next); +					fnd->pml_next = pml; +				} +				ans = 1; +			} +		done: +			if ((!svc_sendreply(xprt, xdr_long, (caddr_t)&ans)) && +			    debugging) { +				fprintf(stderr, "svc_sendreply\n"); +				abort(); +			} +		} +		break; + +	case PMAPPROC_UNSET: +		/* +		 * Remove a program,version to port mapping. +		 */ +		if (!svc_getargs(xprt, xdr_pmap, ®)) +			svcerr_decode(xprt); +		else { +			ans = 0; +			for (prevpml = NULL, pml = pmaplist; pml != NULL; ) { +				if ((pml->pml_map.pm_prog != reg.pm_prog) || +					(pml->pml_map.pm_vers != reg.pm_vers)) { +					/* both pml & prevpml move forwards */ +					prevpml = pml; +					pml = pml->pml_next; +					continue; +				} +				/* found it; pml moves forward, prevpml stays */ +				ans = 1; +				t = (caddr_t)pml; +				pml = pml->pml_next; +				if (prevpml == NULL) +					pmaplist = pml; +				else +					prevpml->pml_next = pml; +				free(t); +			} +			if ((!svc_sendreply(xprt, xdr_long, (caddr_t)&ans)) && +			    debugging) { +				fprintf(stderr, "svc_sendreply\n"); +				abort(); +			} +		} +		break; + +	case PMAPPROC_GETPORT: +		/* +		 * Lookup the mapping for a program,version and return its port +		 */ +		if (!svc_getargs(xprt, xdr_pmap, ®)) +			svcerr_decode(xprt); +		else { +			fnd = find_service(reg.pm_prog, reg.pm_vers, reg.pm_prot); +			if (fnd) +				port = fnd->pml_map.pm_port; +			else +				port = 0; +			if ((!svc_sendreply(xprt, xdr_long, (caddr_t)&port)) && +			    debugging) { +				fprintf(stderr, "svc_sendreply\n"); +				abort(); +			} +		} +		break; + +	case PMAPPROC_DUMP: +		/* +		 * Return the current set of mapped program,version +		 */ +		if (!svc_getargs(xprt, xdr_void, NULL)) +			svcerr_decode(xprt); +		else { +			if ((!svc_sendreply(xprt, xdr_pmaplist, +			    (caddr_t)&pmaplist)) && debugging) { +				fprintf(stderr, "svc_sendreply\n"); +				abort(); +			} +		} +		break; + +	case PMAPPROC_CALLIT: +		/* +		 * Calls a procedure on the local machine.  If the requested +		 * procedure is not registered this procedure does not return +		 * error information!! +		 * This procedure is only supported on rpc/udp and calls via  +		 * rpc/udp.  It passes null authentication parameters. +		 */ +		callit(rqstp, xprt); +		break; + +	default: +		svcerr_noproc(xprt); +		break; +	} +} + + +/* + * Stuff for the rmtcall service + */ +#define ARGSIZE 9000 + +typedef struct encap_parms { +	u_long arglen; +	char *args; +}; + +static bool_t +xdr_encap_parms(xdrs, epp) +	XDR *xdrs; +	struct encap_parms *epp; +{ + +	return (xdr_bytes(xdrs, &(epp->args), &(epp->arglen), ARGSIZE)); +} + +typedef struct rmtcallargs { +	u_long	rmt_prog; +	u_long	rmt_vers; +	u_long	rmt_port; +	u_long	rmt_proc; +	struct encap_parms rmt_args; +}; + +static bool_t +xdr_rmtcall_args(xdrs, cap) +	register XDR *xdrs; +	register struct rmtcallargs *cap; +{ + +	/* does not get a port number */ +	if (xdr_u_long(xdrs, &(cap->rmt_prog)) && +	    xdr_u_long(xdrs, &(cap->rmt_vers)) && +	    xdr_u_long(xdrs, &(cap->rmt_proc))) { +		return (xdr_encap_parms(xdrs, &(cap->rmt_args))); +	} +	return (FALSE); +} + +static bool_t +xdr_rmtcall_result(xdrs, cap) +	register XDR *xdrs; +	register struct rmtcallargs *cap; +{ +	if (xdr_u_long(xdrs, &(cap->rmt_port))) +		return (xdr_encap_parms(xdrs, &(cap->rmt_args))); +	return (FALSE); +} + +/* + * only worries about the struct encap_parms part of struct rmtcallargs. + * The arglen must already be set!! + */ +static bool_t +xdr_opaque_parms(xdrs, cap) +	XDR *xdrs; +	struct rmtcallargs *cap; +{ + +	return (xdr_opaque(xdrs, cap->rmt_args.args, cap->rmt_args.arglen)); +} + +/* + * This routine finds and sets the length of incoming opaque paraters + * and then calls xdr_opaque_parms. + */ +static bool_t +xdr_len_opaque_parms(xdrs, cap) +	register XDR *xdrs; +	struct rmtcallargs *cap; +{ +	register u_int beginpos, lowpos, highpos, currpos, pos; + +	beginpos = lowpos = pos = xdr_getpos(xdrs); +	highpos = lowpos + ARGSIZE; +	while ((int)(highpos - lowpos) >= 0) { +		currpos = (lowpos + highpos) / 2; +		if (xdr_setpos(xdrs, currpos)) { +			pos = currpos; +			lowpos = currpos + 1; +		} else { +			highpos = currpos - 1; +		} +	} +	xdr_setpos(xdrs, beginpos); +	cap->rmt_args.arglen = pos - beginpos; +	return (xdr_opaque_parms(xdrs, cap)); +} + +/* + * Call a remote procedure service + * This procedure is very quiet when things go wrong. + * The proc is written to support broadcast rpc.  In the broadcast case, + * a machine should shut-up instead of complain, less the requestor be + * overrun with complaints at the expense of not hearing a valid reply ... + * + * This now forks so that the program & process that it calls can call  + * back to the portmapper. + */ +static +callit(rqstp, xprt) +	struct svc_req *rqstp; +	SVCXPRT *xprt; +{ +	struct rmtcallargs a; +	struct pmaplist *pml; +	u_short port; +	struct sockaddr_in me; +	int pid, socket = -1; +	CLIENT *client; +	struct authunix_parms *au = (struct authunix_parms *)rqstp->rq_clntcred; +	struct timeval timeout; +	char buf[ARGSIZE]; + +	timeout.tv_sec = 5; +	timeout.tv_usec = 0; +	a.rmt_args.args = buf; +	if (!svc_getargs(xprt, xdr_rmtcall_args, &a)) +	    return; +	if ((pml = find_service(a.rmt_prog, a.rmt_vers, IPPROTO_UDP)) == NULL) +	    return; +	/* +	 * fork a child to do the work.  Parent immediately returns. +	 * Child exits upon completion. +	 */ +	if ((pid = fork()) != 0) { +		if (debugging && (pid < 0)) { +			fprintf(stderr, "portmap CALLIT: cannot fork.\n"); +		} +		return; +	} +	port = pml->pml_map.pm_port; +	get_myaddress(&me); +	me.sin_port = htons(port); +	client = clntudp_create(&me, a.rmt_prog, a.rmt_vers, timeout, &socket); +	if (client != (CLIENT *)NULL) { +		if (rqstp->rq_cred.oa_flavor == AUTH_UNIX) { +			client->cl_auth = authunix_create(au->aup_machname, +			   au->aup_uid, au->aup_gid, au->aup_len, au->aup_gids); +		} +		a.rmt_port = (u_long)port; +		if (clnt_call(client, a.rmt_proc, xdr_opaque_parms, &a, +		    xdr_len_opaque_parms, &a, timeout) == RPC_SUCCESS) { +			svc_sendreply(xprt, xdr_rmtcall_result, &a); +		} +		AUTH_DESTROY(client->cl_auth); +		clnt_destroy(client); +	} +	(void)close(socket); +	exit(0); +} + +void +reap() +{ +	while (wait3(NULL, WNOHANG, NULL) > 0); +} diff --git a/lib/librpc/etc/rpc b/lib/librpc/etc/rpc new file mode 100644 index 000000000000..bebfb51b731a --- /dev/null +++ b/lib/librpc/etc/rpc @@ -0,0 +1,33 @@ +# +# rpc 88/08/01 4.0 RPCSRC; from 1.12   88/02/07 SMI +# +portmapper	100000	portmap sunrpc +rstatd		100001	rstat rstat_svc rup perfmeter +rusersd		100002	rusers +nfs		100003	nfsprog +ypserv		100004	ypprog +mountd		100005	mount showmount +ypbind		100007 +walld		100008	rwall shutdown +yppasswdd	100009	yppasswd +etherstatd	100010	etherstat +rquotad		100011	rquotaprog quota rquota +sprayd		100012	spray +3270_mapper	100013 +rje_mapper	100014 +selection_svc	100015	selnsvc +database_svc	100016 +rexd		100017	rex +alis		100018 +sched		100019 +llockmgr	100020 +nlockmgr	100021 +x25.inr		100022 +statmon		100023 +status		100024 +bootparam	100026 +ypupdated	100028	ypupdate +keyserv		100029	keyserver +tfsd		100037  +nsed		100038 +nsemntd		100039 diff --git a/lib/librpc/etc/rpcinfo.c b/lib/librpc/etc/rpcinfo.c new file mode 100644 index 000000000000..961f9b0b2d75 --- /dev/null +++ b/lib/librpc/etc/rpcinfo.c @@ -0,0 +1,665 @@ +/* @(#)rpcinfo.c	2.2 88/08/11 4.0 RPCSRC */ +#ifndef lint +static	char sccsid[] = "@(#)rpcinfo.c 1.22 87/08/12 SMI"; +#endif + +/* + * Copyright (C) 1986, Sun Microsystems, Inc. + */ + +/* + * rpcinfo: ping a particular rpc program + *     or dump the portmapper + */ + +/* + * Sun RPC is a product of Sun Microsystems, Inc. and is provided for + * unrestricted use provided that this legend is included on all tape + * media and as a part of the software program in whole or part.  Users + * may copy or modify Sun RPC without charge, but are not authorized + * to license or distribute it to anyone else except as part of a product or + * program developed by the user. + *  + * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE + * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR + * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. + *  + * Sun RPC is provided with no support and without any obligation on the + * part of Sun Microsystems, Inc. to assist in its use, correction, + * modification or enhancement. + *  + * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE + * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC + * OR ANY PART THEREOF. + *  + * In no event will Sun Microsystems, Inc. be liable for any lost revenue + * or profits or other special, indirect and consequential damages, even if + * Sun has been advised of the possibility of such damages. + *  + * Sun Microsystems, Inc. + * 2550 Garcia Avenue + * Mountain View, California  94043 + */ + +#include <rpc/rpc.h> +#include <stdio.h> +#include <sys/socket.h> +#include <netdb.h> +#include <rpc/pmap_prot.h> +#include <rpc/pmap_clnt.h> +#include <signal.h> +#include <ctype.h> + +#define MAXHOSTLEN 256 + +#define	MIN_VERS	((u_long) 0) +#define	MAX_VERS	((u_long) 4294967295L) + +static void	udpping(/*u_short portflag, int argc, char **argv*/); +static void	tcpping(/*u_short portflag, int argc, char **argv*/); +static int	pstatus(/*CLIENT *client, u_long prognum, u_long vers*/); +static void	pmapdump(/*int argc, char **argv*/); +static bool_t	reply_proc(/*void *res, struct sockaddr_in *who*/); +static void	brdcst(/*int argc, char **argv*/); +static void	deletereg(/* int argc, char **argv */) ; +static void	usage(/*void*/); +static u_long	getprognum(/*char *arg*/); +static u_long	getvers(/*char *arg*/); +static void	get_inet_address(/*struct sockaddr_in *addr, char *host*/); +extern u_long inet_addr();  /* in 4.2BSD, arpa/inet.h called that a in_addr */ +extern char *inet_ntoa(); + +/* + * Functions to be performed. + */ +#define	NONE		0	/* no function */ +#define	PMAPDUMP	1	/* dump portmapper registrations */ +#define	TCPPING		2	/* ping TCP service */ +#define	UDPPING		3	/* ping UDP service */ +#define	BRDCST		4	/* ping broadcast UDP service */ +#define DELETES		5	/* delete registration for the service */ + +int +main(argc, argv) +	int argc; +	char **argv; +{ +	register int c; +	extern char *optarg; +	extern int optind; +	int errflg; +	int function; +	u_short portnum; + +	function = NONE; +	portnum = 0; +	errflg = 0; +	while ((c = getopt(argc, argv, "ptubdn:")) != EOF) { +		switch (c) { + +		case 'p': +			if (function != NONE) +				errflg = 1; +			else +				function = PMAPDUMP; +			break; + +		case 't': +			if (function != NONE) +				errflg = 1; +			else +				function = TCPPING; +			break; + +		case 'u': +			if (function != NONE) +				errflg = 1; +			else +				function = UDPPING; +			break; + +		case 'b': +			if (function != NONE) +				errflg = 1; +			else +				function = BRDCST; +			break; + +		case 'n': +			portnum = (u_short) atoi(optarg);   /* hope we don't get bogus # */ +			break; + +		case 'd': +			if (function != NONE) +				errflg = 1; +			else +				function = DELETES; +			break; + +		case '?': +			errflg = 1; +		} +	} + +	if (errflg || function == NONE) { +		usage(); +		return (1); +	} + +	switch (function) { + +	case PMAPDUMP: +		if (portnum != 0) { +			usage(); +			return (1); +		} +		pmapdump(argc - optind, argv + optind); +		break; + +	case UDPPING: +		udpping(portnum, argc - optind, argv + optind); +		break; + +	case TCPPING: +		tcpping(portnum, argc - optind, argv + optind); +		break; + +	case BRDCST: +		if (portnum != 0) { +			usage(); +			return (1); +		} +		brdcst(argc - optind, argv + optind); +		break; + +	case DELETES: +		deletereg(argc - optind, argv + optind); +		break; +	} + +	return (0); +} +		 +static void +udpping(portnum, argc, argv) +	u_short portnum; +	int argc; +	char **argv; +{ +	struct timeval to; +	struct sockaddr_in addr; +	enum clnt_stat rpc_stat; +	CLIENT *client; +	u_long prognum, vers, minvers, maxvers; +	int sock = RPC_ANYSOCK; +	struct rpc_err rpcerr; +	int failure; +     +	if (argc < 2 || argc > 3) { +		usage(); +		exit(1); +	} +	prognum = getprognum(argv[1]); +	get_inet_address(&addr, argv[0]); +	/* Open the socket here so it will survive calls to clnt_destroy */ +	sock = socket( AF_INET, SOCK_DGRAM, IPPROTO_UDP); +	if (sock < 0) { +		perror("rpcinfo: socket"); +		exit(1); +	} +	failure = 0; +	if (argc == 2) { +		/* +		 * A call to version 0 should fail with a program/version +		 * mismatch, and give us the range of versions supported. +		 */ +		addr.sin_port = htons(portnum); +		to.tv_sec = 5; +		to.tv_usec = 0; +		if ((client = clntudp_create(&addr, prognum, (u_long)0, +		    to, &sock)) == NULL) { +			clnt_pcreateerror("rpcinfo"); +			printf("program %lu is not available\n", +			    prognum); +			exit(1); +		} +		to.tv_sec = 10; +		to.tv_usec = 0; +		rpc_stat = clnt_call(client, NULLPROC, xdr_void, (char *)NULL, +		    xdr_void, (char *)NULL, to); +		if (rpc_stat == RPC_PROGVERSMISMATCH) { +			clnt_geterr(client, &rpcerr); +			minvers = rpcerr.re_vers.low; +			maxvers = rpcerr.re_vers.high; +		} else if (rpc_stat == RPC_SUCCESS) { +			/* +			 * Oh dear, it DOES support version 0. +			 * Let's try version MAX_VERS. +			 */ +			addr.sin_port = htons(portnum); +			to.tv_sec = 5; +			to.tv_usec = 0; +			if ((client = clntudp_create(&addr, prognum, MAX_VERS, +			    to, &sock)) == NULL) { +				clnt_pcreateerror("rpcinfo"); +				printf("program %lu version %lu is not available\n", +				    prognum, MAX_VERS); +				exit(1); +			} +			to.tv_sec = 10; +			to.tv_usec = 0; +			rpc_stat = clnt_call(client, NULLPROC, xdr_void, +			    (char *)NULL, xdr_void, (char *)NULL, to); +			if (rpc_stat == RPC_PROGVERSMISMATCH) { +				clnt_geterr(client, &rpcerr); +				minvers = rpcerr.re_vers.low; +				maxvers = rpcerr.re_vers.high; +			} else if (rpc_stat == RPC_SUCCESS) { +				/* +				 * It also supports version MAX_VERS. +				 * Looks like we have a wise guy. +				 * OK, we give them information on all +				 * 4 billion versions they support... +				 */ +				minvers = 0; +				maxvers = MAX_VERS; +			} else { +				(void) pstatus(client, prognum, MAX_VERS); +				exit(1); +			} +		} else { +			(void) pstatus(client, prognum, (u_long)0); +			exit(1); +		} +		clnt_destroy(client); +		for (vers = minvers; vers <= maxvers; vers++) { +			addr.sin_port = htons(portnum); +			to.tv_sec = 5; +			to.tv_usec = 0; +			if ((client = clntudp_create(&addr, prognum, vers, +			    to, &sock)) == NULL) { +				clnt_pcreateerror("rpcinfo"); +				printf("program %lu version %lu is not available\n", +				    prognum, vers); +				exit(1); +			} +			to.tv_sec = 10; +			to.tv_usec = 0; +			rpc_stat = clnt_call(client, NULLPROC, xdr_void, +			    (char *)NULL, xdr_void, (char *)NULL, to); +			if (pstatus(client, prognum, vers) < 0) +				failure = 1; +			clnt_destroy(client); +		} +	} +	else { +		vers = getvers(argv[2]); +		addr.sin_port = htons(portnum); +		to.tv_sec = 5; +		to.tv_usec = 0; +		if ((client = clntudp_create(&addr, prognum, vers, +		    to, &sock)) == NULL) { +			clnt_pcreateerror("rpcinfo"); +			printf("program %lu version %lu is not available\n", +			    prognum, vers); +			exit(1); +		} +		to.tv_sec = 10; +		to.tv_usec = 0; +		rpc_stat = clnt_call(client, 0, xdr_void, (char *)NULL, +		    xdr_void, (char *)NULL, to); +		if (pstatus(client, prognum, vers) < 0) +			failure = 1; +	} +	(void) close(sock); /* Close it up again */ +	if (failure) +		exit(1); +} + +static void +tcpping(portnum, argc, argv) +	u_short portnum; +	int argc; +	char **argv; +{ +	struct timeval to; +	struct sockaddr_in addr; +	enum clnt_stat rpc_stat; +	CLIENT *client; +	u_long prognum, vers, minvers, maxvers; +	int sock = RPC_ANYSOCK; +	struct rpc_err rpcerr; +	int failure; + +	if (argc < 2 || argc > 3) { +		usage(); +		exit(1); +	} +	prognum = getprognum(argv[1]); +	get_inet_address(&addr, argv[0]); +	failure = 0; +	if (argc == 2) { +		/* +		 * A call to version 0 should fail with a program/version +		 * mismatch, and give us the range of versions supported. +		 */ +		addr.sin_port = htons(portnum); +		if ((client = clnttcp_create(&addr, prognum, MIN_VERS, +		    &sock, 0, 0)) == NULL) { +			clnt_pcreateerror("rpcinfo"); +			printf("program %lu is not available\n", +			    prognum); +			exit(1); +		} +		to.tv_sec = 10; +		to.tv_usec = 0; +		rpc_stat = clnt_call(client, NULLPROC, xdr_void, (char *)NULL, +		    xdr_void, (char *)NULL, to); +		if (rpc_stat == RPC_PROGVERSMISMATCH) { +			clnt_geterr(client, &rpcerr); +			minvers = rpcerr.re_vers.low; +			maxvers = rpcerr.re_vers.high; +		} else if (rpc_stat == RPC_SUCCESS) { +			/* +			 * Oh dear, it DOES support version 0. +			 * Let's try version MAX_VERS. +			 */ +			addr.sin_port = htons(portnum); +			if ((client = clnttcp_create(&addr, prognum, MAX_VERS, +			    &sock, 0, 0)) == NULL) { +				clnt_pcreateerror("rpcinfo"); +				printf("program %lu version %lu is not available\n", +				    prognum, MAX_VERS); +				exit(1); +			} +			to.tv_sec = 10; +			to.tv_usec = 0; +			rpc_stat = clnt_call(client, NULLPROC, xdr_void, +			    (char *)NULL, xdr_void, (char *)NULL, to); +			if (rpc_stat == RPC_PROGVERSMISMATCH) { +				clnt_geterr(client, &rpcerr); +				minvers = rpcerr.re_vers.low; +				maxvers = rpcerr.re_vers.high; +			} else if (rpc_stat == RPC_SUCCESS) { +				/* +				 * It also supports version MAX_VERS. +				 * Looks like we have a wise guy. +				 * OK, we give them information on all +				 * 4 billion versions they support... +				 */ +				minvers = 0; +				maxvers = MAX_VERS; +			} else { +				(void) pstatus(client, prognum, MAX_VERS); +				exit(1); +			} +		} else { +			(void) pstatus(client, prognum, MIN_VERS); +			exit(1); +		} +		clnt_destroy(client); +		(void) close(sock); +		sock = RPC_ANYSOCK; /* Re-initialize it for later */ +		for (vers = minvers; vers <= maxvers; vers++) { +			addr.sin_port = htons(portnum); +			if ((client = clnttcp_create(&addr, prognum, vers, +			    &sock, 0, 0)) == NULL) { +				clnt_pcreateerror("rpcinfo"); +				printf("program %lu version %lu is not available\n", +				    prognum, vers); +				exit(1); +			} +			to.tv_usec = 0; +			to.tv_sec = 10; +			rpc_stat = clnt_call(client, 0, xdr_void, (char *)NULL, +			    xdr_void, (char *)NULL, to); +			if (pstatus(client, prognum, vers) < 0) +				failure = 1; +			clnt_destroy(client); +			(void) close(sock); +			sock = RPC_ANYSOCK; +		} +	} +	else { +		vers = getvers(argv[2]); +		addr.sin_port = htons(portnum); +		if ((client = clnttcp_create(&addr, prognum, vers, &sock, +		    0, 0)) == NULL) { +			clnt_pcreateerror("rpcinfo"); +			printf("program %lu version %lu is not available\n", +			    prognum, vers); +			exit(1); +		} +		to.tv_usec = 0; +		to.tv_sec = 10; +		rpc_stat = clnt_call(client, 0, xdr_void, (char *)NULL, +		    xdr_void, (char *)NULL, to); +		if (pstatus(client, prognum, vers) < 0) +			failure = 1; +	} +	if (failure) +		exit(1); +} + +/* + * This routine should take a pointer to an "rpc_err" structure, rather than + * a pointer to a CLIENT structure, but "clnt_perror" takes a pointer to + * a CLIENT structure rather than a pointer to an "rpc_err" structure. + * As such, we have to keep the CLIENT structure around in order to print + * a good error message. + */ +static int +pstatus(client, prognum, vers) +	register CLIENT *client; +	u_long prognum; +	u_long vers; +{ +	struct rpc_err rpcerr; + +	clnt_geterr(client, &rpcerr); +	if (rpcerr.re_status != RPC_SUCCESS) { +		clnt_perror(client, "rpcinfo"); +		printf("program %lu version %lu is not available\n", +		    prognum, vers); +		return (-1); +	} else { +		printf("program %lu version %lu ready and waiting\n", +		    prognum, vers); +		return (0); +	} +} + +static void +pmapdump(argc, argv) +	int argc; +	char **argv; +{ +	struct sockaddr_in server_addr; +	register struct hostent *hp; +	struct pmaplist *head = NULL; +	int socket = RPC_ANYSOCK; +	struct timeval minutetimeout; +	register CLIENT *client; +	struct rpcent *rpc; +	 +	if (argc > 1) { +		usage(); +		exit(1); +	} +	if (argc == 1) +		get_inet_address(&server_addr, argv[0]); +	else { +		bzero((char *)&server_addr, sizeof server_addr); +		server_addr.sin_family = AF_INET; +		if ((hp = gethostbyname("localhost")) != NULL) +			bcopy(hp->h_addr, (caddr_t)&server_addr.sin_addr, +			    hp->h_length); +		else +			server_addr.sin_addr.s_addr = inet_addr("0.0.0.0"); +	} +	minutetimeout.tv_sec = 60; +	minutetimeout.tv_usec = 0; +	server_addr.sin_port = htons(PMAPPORT); +	if ((client = clnttcp_create(&server_addr, PMAPPROG, +	    PMAPVERS, &socket, 50, 500)) == NULL) { +		clnt_pcreateerror("rpcinfo: can't contact portmapper"); +		exit(1); +	} +	if (clnt_call(client, PMAPPROC_DUMP, xdr_void, NULL, +	    xdr_pmaplist, &head, minutetimeout) != RPC_SUCCESS) { +		fprintf(stderr, "rpcinfo: can't contact portmapper: "); +		clnt_perror(client, "rpcinfo"); +		exit(1); +	} +	if (head == NULL) { +		printf("No remote programs registered.\n"); +	} else { +		printf("   program vers proto   port\n"); +		for (; head != NULL; head = head->pml_next) { +			printf("%10ld%5ld", +			    head->pml_map.pm_prog, +			    head->pml_map.pm_vers); +			if (head->pml_map.pm_prot == IPPROTO_UDP) +				printf("%6s",  "udp"); +			else if (head->pml_map.pm_prot == IPPROTO_TCP) +				printf("%6s", "tcp"); +			else +				printf("%6ld",  head->pml_map.pm_prot); +			printf("%7ld",  head->pml_map.pm_port); +			rpc = getrpcbynumber(head->pml_map.pm_prog); +			if (rpc) +				printf("  %s\n", rpc->r_name); +			else +				printf("\n"); +		} +	} +} + +/*  + * reply_proc collects replies from the broadcast.  + * to get a unique list of responses the output of rpcinfo should + * be piped through sort(1) and then uniq(1). + */ + +/*ARGSUSED*/ +static bool_t +reply_proc(res, who) +	void *res;		/* Nothing comes back */ +	struct sockaddr_in *who; /* Who sent us the reply */ +{ +	register struct hostent *hp; + +	hp = gethostbyaddr((char *) &who->sin_addr, sizeof who->sin_addr, +	    AF_INET); +	printf("%s %s\n", inet_ntoa(who->sin_addr), +	    (hp == NULL) ? "(unknown)" : hp->h_name); +	return(FALSE); +} + +static void +brdcst(argc, argv) +	int argc; +	char **argv; +{ +	enum clnt_stat rpc_stat; +	u_long prognum, vers; + +	if (argc != 2) { +		usage(); +		exit(1); +	} +	prognum = getprognum(argv[0]); +	vers = getvers(argv[1]); +	rpc_stat = clnt_broadcast(prognum, vers, NULLPROC, xdr_void, +	    (char *)NULL, xdr_void, (char *)NULL, reply_proc); +	if ((rpc_stat != RPC_SUCCESS) && (rpc_stat != RPC_TIMEDOUT)) { +		fprintf(stderr, "rpcinfo: broadcast failed: %s\n", +		    clnt_sperrno(rpc_stat)); +		exit(1); +	} +	exit(0); +} + +static void +deletereg(argc, argv) +	int argc; +	char **argv; +{	u_long prog_num, version_num ; + +	if (argc != 2) { +		usage() ; +		exit(1) ; +	} +	if (getuid()) { /* This command allowed only to root */ +		fprintf(stderr, "Sorry. You are not root\n") ; +		exit(1) ; +	} +	prog_num = getprognum(argv[0]); +	version_num = getvers(argv[1]); +	if ((pmap_unset(prog_num, version_num)) == 0) { +		fprintf(stderr, "rpcinfo: Could not delete registration for prog %s version %s\n", +			argv[0], argv[1]) ; +		exit(1) ; +	} +} + +static void +usage() +{ +	fprintf(stderr, "Usage: rpcinfo [ -n portnum ] -u host prognum [ versnum ]\n"); +	fprintf(stderr, "       rpcinfo [ -n portnum ] -t host prognum [ versnum ]\n"); +	fprintf(stderr, "       rpcinfo -p [ host ]\n"); +	fprintf(stderr, "       rpcinfo -b prognum versnum\n"); +	fprintf(stderr, "       rpcinfo -d prognum versnum\n") ; +} + +static u_long +getprognum(arg) +	char *arg; +{ +	register struct rpcent *rpc; +	register u_long prognum; + +	if (isalpha(*arg)) { +		rpc = getrpcbyname(arg); +		if (rpc == NULL) { +			fprintf(stderr, "rpcinfo: %s is unknown service\n", +			    arg); +			exit(1); +		} +		prognum = rpc->r_number; +	} else { +		prognum = (u_long) atoi(arg); +	} + +	return (prognum); +} + +static u_long +getvers(arg) +	char *arg; +{ +	register u_long vers; + +	vers = (int) atoi(arg); +	return (vers); +} + +static void +get_inet_address(addr, host) +	struct sockaddr_in *addr; +	char *host; +{ +	register struct hostent *hp; + +	bzero((char *)addr, sizeof *addr); +	addr->sin_addr.s_addr = (u_long) inet_addr(host); +	if (addr->sin_addr.s_addr == -1 || addr->sin_addr.s_addr == 0) { +		if ((hp = gethostbyname(host)) == NULL) { +			fprintf(stderr, "rpcinfo: %s is unknown host\n", host); +			exit(1); +		} +		bcopy(hp->h_addr, (char *)&addr->sin_addr, hp->h_length); +	} +	addr->sin_family = AF_INET; +} diff --git a/lib/librpc/man/man1/rpcgen.1 b/lib/librpc/man/man1/rpcgen.1 new file mode 100644 index 000000000000..6c50cecfb6b2 --- /dev/null +++ b/lib/librpc/man/man1/rpcgen.1 @@ -0,0 +1,197 @@ +.\" Copyright 1991 The Regents of the University of California. +.\" All rights reserved. +.\" +.\" Derived from Sun Microsystems rpcgen.1        2.2 88/08/02 4.0 RPCSRC +.\" +.\" 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. +.\" +.\"	@(#)rpcgen.1	5.4 (Berkeley) 12/30/93 +.\" +.Dd December 30, 1993 +.Dt RPCGEN 1 +.Sh NAME +.Nm rpcgen +.Nd an +.Tn RPC +protocol compiler +.Sh SYNOPSIS +.Nm rpcgen Ar infile +.Nm rpcgen +.Fl c | Fl h | Fl l | +.Fl m +.Op Fl o Ar outfile +.Op Ar infile +.Nm rpcgen Fl s Ar transport +.Op Fl o Ar outfile +.Op Ar infile +.Sh DESCRIPTION +.Nm rpcgen +is a tool that generates +.Tn \&C +code to implement an +.Tn RPC +protocol.  The input to +.Nm rpcgen +is a language similar to C +known as +.Tn RPC +Language (Remote Procedure Call Language).  Information +about the syntax of +.Tn RPC +Language is available in the +.Rs +.%T "Rpcgen Programming Guide" +.Re +.Pp +Available options: +.Bl -tag -width indent +.It Fl c +Compile into +.Dv XDR +routines. +.It Fl h +Compile into +.Tn \&C +data-definitions (a header file) +.It Fl l +Compile into client-side stubs. +.It Fl m +Compile into server-side stubs, but do not generate a +.Em main +routine. +This option is useful for doing callback-routines and for people who +need to write their own +.Em main +routine to do initialization. +.It Fl o Ar outfile +Specify the name of the output file. +If none is specified, standard output is used +.Pf ( Fl c , +.Fl h , +.Fl l +and +.Fl s +modes only). +.It Fl s Ar transport +Compile into server-side stubs, using the given transport.  The +supported transports +are +.Tn UDP +and +.Tn TCP . +This option may be invoked more than once +so as to compile a server that serves multiple transports. +.El +.Pp +.Nm rpcgen +is normally used as in the first synopsis where it takes an input file +and generates four output files. If the +.Ar infile +is named +.Pa proto.x , +then +.Nm rpcgen +will generate a header file in +.Pa proto.h , +.Dv XDR +routines in +.Pa proto_xdr.c , +server-side stubs in +.Pa proto_svc.c , +and client-side stubs in +.Pa proto_clnt.c . +.Pp +The other synopses shown above are used when one does not want to +generate all the output files, but only a particular one.  Their +usage is described in the +.Sx USAGE +section below. +.Pp +The C-preprocessor, +.Xr cpp 1 , +is run on all input files before they are actually +interpreted by +.Nm rpcgen , +so all the +.Xr cpp +directives are legal within an +.Nm rpcgen +input file.  For each type of output file, +.Nm rpcgen +defines a special +.Xr cpp +symbol for use by the +.Nm rpcgen +programmer: +.Pp +.Bl -tag -width "RPC_CLNT" +.It Dv RPC_HDR +defined when compiling into header files +.It Dv RPC_XDR +defined when compiling into +.Dv XDR +routines +.It Dv RPC_SVC +defined when compiling into server-side stubs +.It Dv RPC_CLNT +defined when compiling into client-side stubs +.El +.Pp +In addition, +.Nm rpcgen +does a little preprocessing of its own. +Any line beginning with +.Ql \&% +is passed directly into the output file, uninterpreted by +.Nm rpcgen . +.Pp +You can customize some of your +.Dv XDR +routines by leaving those data +types undefined.  For every data type that is undefined, +.Nm rpcgen +will assume that there exists a routine with the name +.Em xdr_ +prepended to the name of the undefined type. +.Sh SEE ALSO +.Xr cpp 1 +.Rs +.%T "Rpcgen Programming Guide" +.%I "Sun Microsystems" +.Re +.Sh BUGS +.Pp +Nesting is not supported. +As a work-around, structures can be declared at +top-level, and their name used inside other structures in order to achieve +the same effect. +.Pp +Name clashes can occur when using program definitions, since the apparent +scoping does not really apply. Most of these can be avoided by giving +unique names for programs, versions, procedures and types. diff --git a/lib/librpc/man/man1/rstat.1 b/lib/librpc/man/man1/rstat.1 new file mode 100644 index 000000000000..52eaa31c924e --- /dev/null +++ b/lib/librpc/man/man1/rstat.1 @@ -0,0 +1,57 @@ +.\" @(#)rstat.1	2.1 88/08/03 4.0 RPCSRC +.TH RSTAT 1 "3 August 1988" +.SH NAME +rstat \- remote status display +.SH SYNOPSIS +.B rstat +.B host +.SH DESCRIPTION +.LP +.B rstat +displays a summary of the current system status of a particular +.BR host . +The output shows the current time of day, how long the system has +been up, +and the load averages. +The load average numbers give the number of jobs in the run queue +averaged over 1, 5 and 15 minutes. +.PP +The +.B rstat_svc(8c) +daemon must be running on the remote host for this command to +work. +.B rstat +uses an RPC protocol defined in /usr/include/rpcsvc/rstat.x. +.SH EXAMPLE +.RS +.ft B +.nf +example% rstat otherhost +7:36am  up 6 days, 16:45,  load average: 0.20, 0.23, 0.18 +example% +.ft R +.fi +.RE +.SH DIAGNOSTICS +.LP +rstat: RPC: Program not registered +.IP +The +.B rstat_svc +daemon has not been started on the remote host. +.LP +rstat: RPC: Timed out +.IP +A communication error occurred.  Either the network is +excessively congested, or the +.B rstat_svc +daemon has terminated on the remote host. +.LP +rstat: RPC: Port mapper failure - RPC: Timed out +.IP +The remote host is not running the portmapper (see +.BR portmap(8c) ), +and cannot accommodate any RPC-based services.  The host may be down. +.SH "SEE ALSO" +.BR portmap (8c), +.BR rstat_svc (8c) diff --git a/lib/librpc/man/man3/bindresvport.3n b/lib/librpc/man/man3/bindresvport.3n new file mode 100644 index 000000000000..1fb1f9a30600 --- /dev/null +++ b/lib/librpc/man/man3/bindresvport.3n @@ -0,0 +1,27 @@ +.\" @(#)bindresvport.3n	2.2 88/08/02 4.0 RPCSRC; from 1.7 88/03/14 SMI +.TH BINDRESVPORT 3N  "22 november 1987" +.SH NAME +bindresvport \- bind a socket to a privileged IP port +.SH SYNOPSIS +.nf +.B #include <sys/types.h> +.B #include <netinet/in.h> +.LP +.B int bindresvport(sd, sin) +.B int sd; +.B struct sockaddr_in \(**sin; +.fi +.SH DESCRIPTION +.LP +.B bindresvport(\|) +is used to bind a socket descriptor to a privileged +.SM IP +port, that is, a +port number in the range 0-1023. +The routine returns 0 if it is successful, +otherwise \-1 is returned and +.B errno +set to reflect the cause of the error. +.LP +Only root can bind to a privileged port; this call will fail for any +other users. diff --git a/lib/librpc/man/man3/getrpcent.3n b/lib/librpc/man/man3/getrpcent.3n new file mode 100644 index 000000000000..f500c01b075f --- /dev/null +++ b/lib/librpc/man/man3/getrpcent.3n @@ -0,0 +1,109 @@ +.\" @(#)getrpcent.3n	2.2 88/08/02 4.0 RPCSRC; from 1.11 88/03/14 SMI +.TH GETRPCENT 3N "14 December 1987" +.SH NAME +getrpcent, getrpcbyname, getrpcbynumber \- get RPC entry +.SH SYNOPSIS +.nf +.ft B +#include <netdb.h> +.LP +.ft B +struct rpcent *getrpcent(\|) +.LP +.ft B +struct rpcent *getrpcbyname(name) +char *name; +.LP +.ft B +struct rpcent *getrpcbynumber(number) +int number; +.LP +.ft B +setrpcent (stayopen) +int stayopen +.LP +.ft B +endrpcent (\|) +.fi +.SH DESCRIPTION +.LP +.BR getrpcent(\|) , +.BR getrpcbyname(\|) , +and +.B getrpcbynumber(\|) +each return a pointer to an object with the +following structure +containing the broken-out +fields of a line in the rpc program number data base, +.BR /etc/rpc . +.RS +.LP +.nf +.ft B +struct	rpcent { +	char	*r_name;	/* name of server for this rpc program */ +	char	**r_aliases;	/* alias list */ +	long	r_number;	/* rpc program number */ +}; +.ft R +.fi +.RE +.LP +The members of this structure are: +.RS +.PD 0 +.TP 20 +.B r_name +The name of the server for this rpc program. +.TP 20 +.B r_aliases +A zero terminated list of alternate names for the rpc program. +.TP  20 +.B r_number +The rpc program number for this service. +.PD +.RE +.LP +.B getrpcent(\|) +reads the next line of the file, opening the file if necessary. +.LP +.B getrpcent(\|) +opens and rewinds the file.  If the +.I stayopen +flag is non-zero, +the net data base will not be closed after each call to +.B getrpcent(\|) +(either directly, or indirectly through one of +the other \*(lqgetrpc\*(rq calls). +.LP +.B endrpcent +closes the file. +.LP +.B getrpcbyname(\|) +and +.B getrpcbynumber(\|) +sequentially search from the beginning +of the file until a matching rpc program name or +program number is found, or until end-of-file is encountered. +.SH FILES +.PD 0 +.TP 20 +.B /etc/rpc +.PD +.SH "SEE ALSO" +.BR rpc (5), +.BR rpcinfo (8C), +.BR ypserv (8) +.SH DIAGNOSTICS +.LP +A +.SM NULL +pointer is returned on  +.SM EOF +or error. +.SH BUGS +.LP +All information +is contained in a static area +so it must be copied if it is +to be saved. diff --git a/lib/librpc/man/man3/getrpcport.3r b/lib/librpc/man/man3/getrpcport.3r new file mode 100644 index 000000000000..0323d34a07c8 --- /dev/null +++ b/lib/librpc/man/man3/getrpcport.3r @@ -0,0 +1,31 @@ +.\" @(#)getrpcport.3r	2.2 88/08/02 4.0 RPCSRC; from 1.12 88/02/26 SMI +.TH GETRPCPORT 3R "6 October 1987" +.SH NAME +getrpcport \- get RPC port number +.SH SYNOPSIS +.ft B +.nf +int getrpcport(host, prognum, versnum, proto) +	char *host; +	int prognum, versnum, proto; +.fi +.SH DESCRIPTION +.IX getrpcport "" "\fLgetrpcport\fR \(em get RPC port number" +.B getrpcport(\|) +returns the port number for version +.I versnum +of the RPC program +.I prognum +running on +.I host +and using protocol +.IR proto . +It returns 0 if it cannot contact the portmapper, or if +.I prognum +is not registered.  If +.I prognum +is registered but not with version +.IR versnum , +it will still return a port number (for some version of the program) +indicating that the program is indeed registered. +The version mismatch will be detected upon the first call to the service. diff --git a/lib/librpc/man/man3/rpc.3n b/lib/librpc/man/man3/rpc.3n new file mode 100644 index 000000000000..b5a2b92fce76 --- /dev/null +++ b/lib/librpc/man/man3/rpc.3n @@ -0,0 +1,1729 @@ +.\" @(#)rpc.3n	2.4 88/08/08 4.0 RPCSRC; from 1.19 88/06/24 SMI +.TH RPC 3N "16 February 1988" +.SH NAME +rpc \- library routines for remote procedure calls +.SH SYNOPSIS AND DESCRIPTION +These routines allow C programs to make procedure +calls on other machines across the network. +First, the client calls a procedure to send a +data packet to the server. +Upon receipt of the packet, the server calls a dispatch routine +to perform the requested service, and then sends back a +reply. +Finally, the procedure call returns to the client. +.LP +Routines that are used for Secure RPC (DES authentication) are described in +.BR rpc_secure (3N). +Secure RPC can be used only if DES encryption is available. +.LP +.ft B +.nf +.sp .5 +#include <rpc/rpc.h> +.fi +.ft R +.br +.if t .ne 8 +.LP +.ft B +.nf +.sp .5 +void +auth_destroy(auth) +\s-1AUTH\s0 *auth; +.fi +.ft R +.IP +A macro that destroys the authentication information associated with +.IR auth . +Destruction usually involves deallocation of private data +structures. The use of +.I auth +is undefined after calling +.BR auth_destroy(\|) . +.br +.if t .ne 6 +.LP +.ft B +.nf +.sp .5 +\s-1AUTH\s0 * +authnone_create(\|) +.fi +.ft R +.IP +Create and returns an +.SM RPC +authentication handle that passes nonusable authentication +information with each remote procedure call. This is the +default authentication used by +.SM RPC. +.if t .ne 10 +.LP +.ft B +.nf +.sp .5 +\s-1AUTH\s0 * +authunix_create(host, uid, gid, len, aup_gids) +char *host; +int uid, gid, len, *aup.gids; +.fi +.ft R +.IP +Create and return an +.SM RPC +authentication handle that contains +.UX +authentication information. +The parameter +.I host +is the name of the machine on which the information was +created; +.I uid +is the user's user +.SM ID ; +.I gid +is the user's current group +.SM ID ; +.I len +and +.I aup_gids +refer to a counted array of groups to which the user belongs. +It is easy to impersonate a user. +.br +.if t .ne 5 +.LP +.ft B +.nf +.sp .5 +\s-1AUTH\s0 * +authunix_create_default(\|) +.fi +.ft R +.IP +Calls +.B authunix_create(\|) +with the appropriate parameters. +.br +.if t .ne 13 +.LP +.ft B +.nf +.sp .5 +callrpc(host, prognum, versnum, procnum, inproc, in, outproc, out) +char *host; +u_long prognum, versnum, procnum; +char *in, *out; +xdrproc_t inproc, outproc; +.fi +.ft R +.IP +Call the remote procedure associated with +.IR prognum , +.IR versnum , +and +.I procnum +on the machine, +.IR host . +The parameter +.I in +is the address of the procedure's argument(s), and +.I out +is the address of where to place the result(s); +.I inproc +is used to encode the procedure's parameters, and +.I outproc +is used to decode the procedure's results. +This routine returns zero if it succeeds, or the value of +.B "enum clnt_stat" +cast to an integer if it fails. +The routine +.B clnt_perrno(\|) +is handy for translating failure statuses into messages. +.IP +Warning: calling remote procedures with this routine +uses +.SM UDP/IP +as a transport; see +.B clntudp_create(\|) +for restrictions. +You do not have control of timeouts or authentication using +this routine. +.br +.if t .ne 16 +.LP +.ft B +.nf +.sp .5 +enum clnt_stat +clnt_broadcast(prognum, versnum, procnum, inproc, in, outproc, out, eachresult) +u_long prognum, versnum, procnum; +char *in, *out; +xdrproc_t inproc, outproc; +resultproc_t eachresult; +.fi +.ft R +.IP +Like +.BR callrpc(\|) , +except the call message is broadcast to all locally +connected broadcast nets. Each time it receives a +response, this routine calls +.BR eachresult(\|) , +whose form is: +.IP +.RS 1i +.ft B +.nf +eachresult(out, addr) +char *out; +struct sockaddr_in *addr; +.ft R +.fi +.RE +.IP +where +.I out +is the same as +.I out +passed to +.BR clnt_broadcast(\|) , +except that the remote procedure's output is decoded there; +.I addr +points to the address of the machine that sent the results. +If +.B eachresult(\|) +returns zero, +.B clnt_broadcast(\|) +waits for more replies; otherwise it returns with appropriate +status. +.IP +Warning: broadcast sockets are limited in size to the +maximum transfer unit of the data link. For ethernet, +this value is 1500 bytes. +.br +.if t .ne 13 +.LP +.ft B +.nf +.sp .5 +enum clnt_stat +clnt_call(clnt, procnum, inproc, in, outproc, out, tout) +\s-1CLIENT\s0 *clnt; +u_long +procnum; +xdrproc_t inproc, outproc; +char *in, *out; +struct timeval tout; +.fi +.ft R +.IP +A macro that calls the remote procedure +.I procnum +associated with the client handle, +.IR clnt , +which is obtained with an +.SM RPC +client creation routine such as +.BR clnt_create(\|) . +The parameter +.I in +is the address of the procedure's argument(s), and +.I out +is the address of where to place the result(s); +.I inproc +is used to encode the procedure's parameters, and +.I outproc +is used to decode the procedure's results; +.I tout +is the time allowed for results to come back. +.br +.if t .ne 7 +.LP +.ft B +.nf +.sp .5 +clnt_destroy(clnt) +\s-1CLIENT\s0 *clnt; +.fi +.ft R +.IP +A macro that destroys the client's +.SM RPC +handle. Destruction usually involves deallocation +of private data structures, including +.I clnt +itself.  Use of +.I clnt +is undefined after calling +.BR clnt_destroy(\|) . +If the +.SM RPC +library opened the associated socket, it will close it also. +Otherwise, the socket remains open. +.br +.if t .ne 10 +.LP +.ft B +.nf +.sp .5 +\s-1CLIENT\s0 * +clnt_create(host, prog, vers, proto) +char *host; +u_long prog, vers; +char *proto; +.fi +.ft R +.IP +Generic client creation routine. +.I host +identifies the name of the remote host where the server +is located. +.I proto +indicates which kind of transport protocol to use. The +currently supported values for this field are \(lqudp\(rq +and \(lqtcp\(rq. +Default timeouts are set, but can be modified using +.BR clnt_control(\|) . +.IP +Warning: Using +.SM UDP +has its shortcomings.  Since +.SM UDP\s0-based +.SM RPC +messages can only hold up to 8 Kbytes of encoded data, +this transport cannot be used for procedures that take +large arguments or return huge results. +.br +.if t .ne 10 +.LP +.ft B +.nf +.sp .5 +bool_t +clnt_control(cl, req, info) +\s-1CLIENT\s0 *cl; +char *info; +.fi +.ft R +.IP +A macro used to change or retrieve various information +about a client object. +.I req +indicates the type of operation, and +.I info +is a pointer to the information. For both +.SM UDP +and +.SM TCP\s0, +the supported values of +.I req +and their argument types and what they do are: +.IP +.nf +.ta +2.0i +2.0i +2.0i +.SM CLSET_TIMEOUT\s0	struct timeval	set total timeout +.SM CLGET_TIMEOUT\s0	struct timeval	get total timeout +.fi +.IP +Note: if you set the timeout using +.BR clnt_control(\|) , +the timeout parameter passed to +.B clnt_call(\|) +will be ignored in all future calls. +.IP +.nf +.SM CLGET_SERVER_ADDR\s0	struct sockaddr_in 	get server's address +.fi +.br +.IP +The following operations are valid for +.SM UDP +only: +.IP +.nf +.ta +2.0i ; +2.0i ; +2.0i +.SM CLSET_RETRY_TIMEOUT\s0		struct timeval	set the retry timeout +.SM CLGET_RETRY_TIMEOUT\s0		struct timeval	get the retry timeout +.fi +.br +.IP +The retry timeout is the time that +.SM "UDP RPC" +waits for the server to reply before +retransmitting the request. +.br +.if t .ne 10 +.LP +.ft B +.nf +.sp .5 +clnt_freeres(clnt, outproc, out) +\s-1CLIENT\s0 *clnt; +xdrproc_t outproc; +char *out; +.fi +.ft R +.IP +A macro that frees any data allocated by the +.SM RPC/XDR +system when it decoded the results of an +.SM RPC +call.  The +parameter +.I out +is the address of the results, and +.I outproc +is the +.SM XDR +routine describing the results. +This routine returns one if the results were successfully +freed, +and zero otherwise. +.br +.if t .ne 6 +.LP +.ft B +.nf +.sp .5 +void +clnt_geterr(clnt, errp) +\s-1CLIENT\s0 *clnt; +struct rpc_err *errp; +.fi +.ft R +.IP +A macro that copies the error structure out of the client +handle +to the structure at address +.IR errp . +.br +.if t .ne 8 +.LP +.ft B +.nf +.sp .5 +void +clnt_pcreateerror(s) +char *s; +.fi +.ft R +.IP +Print a message to standard error indicating +why a client +.SM RPC +handle could not be created. +The message is prepended with string +.I s +and a colon. +Used when a +.BR clnt_create(\|) , +.BR clntraw_create(\|) , +.BR clnttcp_create(\|) , +or +.B clntudp_create(\|) +call fails. +.br +.if t .ne 8 +.LP +.ft B +.nf +.sp .5 +void +clnt_perrno(stat) +enum clnt_stat stat; +.fi +.ft R +.IP +Print a message to standard error corresponding +to the condition indicated by +.IR stat . +Used after +.BR callrpc(\|) . +.br +.if t .ne 8 +.LP +.ft B +.nf +.sp .5 +clnt_perror(clnt, s) +\s-1CLIENT\s0 *clnt; +char *s; +.fi +.ft R +.IP +Print a message to standard error indicating why an +.SM RPC +call failed; +.I clnt +is the handle used to do the call. +The message is prepended with string +.I s +and a colon. +Used after +.BR clnt_call(\|) . +.br +.if t .ne 9 +.LP +.ft B +.nf +.sp .5 +char * +clnt_spcreateerror +char *s; +.fi +.ft R +.IP +Like +.BR clnt_pcreateerror(\|) , +except that it returns a string +instead of printing to the standard error. +.IP +Bugs: returns pointer to static data that is overwritten +on each call. +.br +.if t .ne 9 +.LP +.ft B +.nf +.sp .5 +char * +clnt_sperrno(stat) +enum clnt_stat stat; +.fi +.ft R +.IP +Take the same arguments as +.BR clnt_perrno(\|) , +but instead of sending a message to the standard error +indicating why an +.SM RPC +call failed, return a pointer to a string which contains +the message.  The string ends with a +.SM NEWLINE\s0. +.IP +.B clnt_sperrno(\|) +is used instead of +.B clnt_perrno(\|) +if the program does not have a standard error (as a program +running as a server quite likely does not), or if the +programmer +does not want the message to be output with +.BR printf , +or if a message format different than that supported by +.B clnt_perrno(\|) +is to be used. +Note: unlike +.B clnt_sperror(\|) +and +.BR clnt_spcreaterror(\|) , +.B clnt_sperrno(\|) +returns pointer to static data, but the +result will not get overwritten on each call. +.br +.if t .ne 7 +.LP +.ft B +.nf +.sp .5 +char * +clnt_sperror(rpch, s) +\s-1CLIENT\s0 *rpch; +char *s; +.fi +.ft R +.IP +Like +.BR clnt_perror(\|) , +except that (like +.BR clnt_sperrno(\|) ) +it returns a string instead of printing to standard error. +.IP +Bugs: returns pointer to static data that is overwritten +on each call. +.br +.if t .ne 10 +.LP +.ft B +.nf +.sp .5 +\s-1CLIENT\s0 * +clntraw_create(prognum, versnum) +u_long prognum, versnum; +.fi +.ft R +.IP +This routine creates a toy +.SM RPC +client for the remote program +.IR prognum , +version +.IR versnum . +The transport used to pass messages to the service is +actually a buffer within the process's address space, so the +corresponding +.SM RPC +server should live in the same address space; see +.BR svcraw_create(\|) . +This allows simulation of +.SM RPC +and acquisition of +.SM RPC +overheads, such as round trip times, without any +kernel interference. This routine returns +.SM NULL +if it fails. +.br +.if t .ne 15 +.LP +.ft B +.nf +.sp .5 +\s-1CLIENT\s0 * +clnttcp_create(addr, prognum, versnum, sockp, sendsz, recvsz) +struct sockaddr_in *addr; +u_long prognum, versnum; +int *sockp; +u_int sendsz, recvsz; +.fi +.ft R +.IP +This routine creates an +.SM RPC +client for the remote program +.IR prognum , +version +.IR versnum ; +the client uses +.SM TCP/IP +as a transport. The remote program is located at Internet +address +.IR *addr . +If +.\"The following in-line font conversion is necessary for the hyphen indicator +\fB\%addr\->sin_port\fR +is zero, then it is set to the actual port that the remote +program is listening on (the remote +.B portmap +service is consulted for this information). The parameter +.I sockp +is a socket; if it is +.BR \s-1RPC_ANYSOCK\s0 , +then this routine opens a new one and sets +.IR sockp . +Since +.SM TCP\s0-based +.SM RPC +uses buffered +.SM I/O , +the user may specify the size of the send and receive buffers +with the parameters +.I sendsz +and +.IR recvsz ; +values of zero choose suitable defaults. +This routine returns +.SM NULL +if it fails. +.br +.if t .ne 15 +.LP +.ft B +.nf +.sp .5 +\s-1CLIENT\s0 * +clntudp_create(addr, prognum, versnum, wait, sockp) +struct sockaddr_in *addr; +u_long prognum, versnum; +struct timeval wait; +int *sockp; +.fi +.ft R +.IP +This routine creates an +.SM RPC +client for the remote program +.IR prognum , +version +.IR versnum ; +the client uses use +.SM UDP/IP +as a transport. The remote program is located at Internet +address +.IR addr . +If +\fB\%addr\->sin_port\fR +is zero, then it is set to actual port that the remote +program is listening on (the remote +.B portmap +service is consulted for this information). The parameter +.I sockp +is a socket; if it is +.BR \s-1RPC_ANYSOCK\s0 , +then this routine opens a new one and sets +.IR sockp . +The +.SM UDP +transport resends the call message in intervals of +.B wait +time until a response is received or until the call times +out. +The total time for the call to time out is specified by +.BR clnt_call(\|) . +.IP +Warning: since +.SM UDP\s0-based +.SM RPC +messages can only hold up to 8 Kbytes +of encoded data, this transport cannot be used for procedures +that take large arguments or return huge results. +.br +.if t .ne 8 +.LP +.ft B +.nf +.sp .5 +\s-1CLIENT\s0 * +clntudp_bufcreate(addr, prognum, versnum, wait, sockp, sendsize, recosize) +struct sockaddr_in *addr; +u_long prognum, versnum; +struct timeval wait; +int *sockp; +unsigned int sendsize; +unsigned int recosize; +.fi +.ft R +.IP +This routine creates an +.SM RPC +client for the remote program +.IR prognum , +on +.IR versnum ; +the client uses use +.SM UDP/IP +as a transport. The remote program is located at Internet +address +.IR addr . +If +\fB\%addr\->sin_port\fR +is zero, then it is set to actual port that the remote +program is listening on (the remote +.B portmap +service is consulted for this information). The parameter +.I sockp +is a socket; if it is +.BR \s-1RPC_ANYSOCK\s0 , +then this routine opens a new one and sets +.BR sockp . +The +.SM UDP +transport resends the call message in intervals of +.B wait +time until a response is received or until the call times +out. +The total time for the call to time out is specified by +.BR clnt_call(\|) . +.IP +This allows the user to specify the maximun packet size for sending and receiving  +.SM UDP\s0-based +.SM RPC +messages. +.br +.if t .ne 7 +.LP +.ft B +.nf +.sp .5 +void +get_myaddress(addr) +struct sockaddr_in *addr; +.fi +.ft R +.IP +Stuff the machine's +.SM IP +address into +.IR *addr , +without consulting the library routines that deal with +.BR /etc/hosts . +The port number is always set to +.BR htons(\s-1PMAPPORT\s0) . +.br +.if t .ne 10 +.LP +.ft B +.nf +.sp .5 +struct pmaplist * +pmap_getmaps(addr) +struct sockaddr_in *addr; +.fi +.ft R +.IP +A user interface to the +.B portmap +service, which returns a list of the current +.SM RPC +program-to-port mappings +on the host located at +.SM IP +address +.IR *addr . +This routine can return +.SM NULL . +The command +.RB ` "rpcinfo \-p" ' +uses this routine. +.br +.if t .ne 12 +.LP +.ft B +.nf +.sp .5 +u_short +pmap_getport(addr, prognum, versnum, protocol) +struct sockaddr_in *addr; +u_long prognum, versnum, protocol; +.fi +.ft R +.IP +A user interface to the +.B portmap +service, which returns the port number +on which waits a service that supports program number +.IR prognum , +version +.IR versnum , +and speaks the transport protocol associated with +.IR protocol . +The value of +.I protocol +is most likely +.B +.SM IPPROTO_UDP +or  +.BR \s-1IPPROTO_TCP\s0 . +A return value of zero means that the mapping does not exist +or that +the +.SM RPC +system failured to contact the remote +.B portmap +service.  In the latter case, the global variable +.B rpc_createerr(\|) +contains the +.SM RPC +status. +.br +.if t .ne 15 +.LP +.ft B +.nf +.sp .5 +enum clnt_stat +pmap_rmtcall(addr, prognum, versnum, procnum, inproc, in, outproc, out, tout, portp) +struct sockaddr_in *addr; +u_long prognum, versnum, procnum; +char *in, *out; +xdrproc_t inproc, outproc; +struct timeval tout; +u_long *portp; +.fi +.ft R +.IP +A user interface to the +.B portmap +service, which instructs +.B portmap +on the host at +.SM IP +address +.I *addr +to make an +.SM RPC +call on your behalf to a procedure on that host. +The parameter +.I *portp +will be modified to the program's port number if the +procedure +succeeds. The definitions of other parameters are discussed +in +.B callrpc(\|) +and +.BR clnt_call(\|) . +This procedure should be used for a \(lqping\(rq and nothing +else. +See also +.BR clnt_broadcast(\|) . +.br +.if t .ne 9 +.LP +.ft B +.nf +.sp .5 +pmap_set(prognum, versnum, protocol, port) +u_long prognum, versnum, protocol; +u_short port; +.fi +.ft R +.IP +A user interface to the +.B portmap +service, which establishes a mapping between the triple +.RI [ prognum , versnum , protocol\fR] +and +.I port +on the machine's +.B portmap +service. The value of +.I protocol +is most likely +.B +.SM IPPROTO_UDP +or  +.BR \s-1IPPROTO_TCP\s0 . +This routine returns one if it succeeds, zero otherwise. +Automatically done by +.BR svc_register(\|) . +.br +.if t .ne 7 +.LP +.ft B +.nf +.sp .5 +pmap_unset(prognum, versnum) +u_long prognum, versnum; +.fi +.ft R +.IP +A user interface to the +.B portmap +service, which destroys all mapping between the triple +.RI [ prognum , versnum , *\fR] +and +.B ports +on the machine's +.B portmap +service. This routine returns one if it succeeds, zero +otherwise. +.br +.if t .ne 15 +.LP +.ft B +.nf +.sp .5 +registerrpc(prognum, versnum, procnum, procname, inproc, outproc) +u_long prognum, versnum, procnum; +char *(*procname) (\|) ; +xdrproc_t inproc, outproc; +.fi +.ft R +.IP +Register procedure +.I procname +with the +.SM RPC +service package.  If a request arrives for program +.IR prognum , +version +.IR versnum , +and procedure +.IR procnum , +.I procname +is called with a pointer to its parameter(s); +.I progname +should return a pointer to its static result(s); +.I inproc +is used to decode the parameters while +.I outproc +is used to encode the results. +This routine returns zero if the registration succeeded, \-1 +otherwise. +.IP +Warning: remote procedures registered in this form +are accessed using the +.SM UDP/IP +transport; see +.B svcudp_create(\|) +for restrictions. +.br +.if t .ne 5 +.LP +.ft B +.nf +.sp .5 +struct rpc_createerr     rpc_createerr; +.fi +.ft R +.IP +A global variable whose value is set by any +.SM RPC +client creation routine +that does not succeed.  Use the routine +.B clnt_pcreateerror(\|) +to print the reason why. +.if t .ne 7 +.LP +.ft B +.nf +.sp .5 +svc_destroy(xprt) +\s-1SVCXPRT\s0 * +xprt; +.fi +.ft R +.IP +A macro that destroys the +.SM RPC +service transport handle, +.IR xprt . +Destruction usually involves deallocation +of private data structures, including +.I xprt +itself.  Use of +.I xprt +is undefined after calling this routine. +.br +.if t .ne 8 +.LP +.ft B +.nf +.sp .5 +fd_set svc_fdset; +.fi +.ft R +.IP +A global variable reflecting the +.SM RPC +service side's +read file descriptor bit mask; it is suitable as a parameter +to the +.B select +system call. This is only of interest +if a service implementor does not call +.BR svc_run(\|) , +but rather does his own asynchronous event processing. +This variable is read-only (do not pass its address to +.BR select !), +yet it may change after calls to +.B svc_getreqset(\|) +or any creation routines. +.br +.if t .ne 6 +.LP +.ft B +.nf +.sp .5 +int svc_fds; +.fi +.ft R +.IP +Similar to +.BR svc_fedset(\|) , +but limited to 32 descriptors. This +interface is obsoleted by +.BR svc_fdset(\|) . +.br +.if t .ne 9 +.LP +.ft B +.nf +.sp .5 +svc_freeargs(xprt, inproc, in) +\s-1SVCXPRT\s0 *xprt; +xdrproc_t inproc; +char *in; +.fi +.ft R +.IP +A macro that frees any data allocated by the +.SM RPC/XDR +system when it decoded the arguments to a service procedure +using +.BR svc_getargs(\|) . +This routine returns 1 if the results were successfully +freed, +and zero otherwise. +.br +.if t .ne 10 +.LP +.ft B +.nf +.sp .5 +svc_getargs(xprt, inproc, in) +\s-1SVCXPRT\s0 *xprt; +xdrproc_t inproc; +char *in; +.fi +.ft R +.IP +A macro that decodes the arguments of an +.SM RPC +request +associated with the +.SM RPC +service transport handle, +.IR xprt . +The parameter +.I in +is the address where the arguments will be placed; +.I inproc +is the +.SM XDR +routine used to decode the arguments. +This routine returns one if decoding succeeds, and zero +otherwise. +.br +.if t .ne 9 +.LP +.ft B +.nf +.sp .5 +struct sockaddr_in * +svc_getcaller(xprt) +\s-1SVCXPRT\s0 *xprt; +.fi +.ft R +.IP +The approved way of getting the network address of the caller +of a procedure associated with the +.SM RPC +service transport handle, +.IR xprt . +.br +.if t .ne 9 +.LP +.ft B +.nf +.sp .5 +svc_getreqset(rdfds) +fd_set *rdfds; +.fi +.ft R +.IP +This routine is only of interest if a service implementor +does not call +.BR svc_run(\|) , +but instead implements custom asynchronous event processing. +It is called when the +.B select +system call has determined that an +.SM RPC +request has arrived on some +.SM RPC +.B socket(s) ; +.I rdfds +is the resultant read file descriptor bit mask. +The routine returns when all sockets associated with the +value of +.I rdfds +have been serviced. +.br +.if t .ne 6 +.LP +.ft B +.nf +.sp .5 +svc_getreq(rdfds) +int rdfds; +.fi +.ft R +.IP +Similar to +.BR svc_getreqset(\|) , +but limited to 32 descriptors. This interface is obsoleted by +.BR svc_getreqset(\|) . +.br +.if t .ne 17 +.LP +.ft B +.nf +.sp .5 +svc_register(xprt, prognum, versnum, dispatch, protocol) +\s-1SVCXPRT\s0 *xprt; +u_long prognum, versnum; +void (*dispatch) (\|); +u_long protocol; +.fi +.ft R +.IP +Associates +.I prognum +and +.I versnum +with the service dispatch procedure, +.IR dispatch . +If +.I protocol +is zero, the service is not registered with the +.B portmap +service.  If +.I protocol +is non-zero, then a mapping of the triple +.RI [ prognum , versnum , protocol\fR] +to +\fB\%xprt\->xp_port\fR +is established with the local +.B portmap +service (generally +.I protocol +is zero, +.B +.SM IPPROTO_UDP +or  +.B +.SM IPPROTO_TCP +). +The procedure +.I dispatch +has the following form: +.RS 1i +.ft B +.nf +dispatch(request, xprt) +struct svc_req *request; +\s-1SVCXPRT\s0 *xprt; +.ft R +.fi +.RE +.IP +The +.B svc_register(\|) +routine returns one if it succeeds, and zero otherwise. +.br +.if t .ne 6 +.LP +.ft B +.nf +.sp .5 +svc_run(\|) +.fi +.ft R +.IP +This routine never returns. It waits for +.SM RPC +requests to arrive, and calls the appropriate service +procedure using +.B svc_getreq(\|) +when one arrives. This procedure is usually waiting for a +.B select(\|) +system call to return. +.br +.if t .ne 9 +.LP +.ft B +.nf +.sp .5 +svc_sendreply(xprt, outproc, out) +\s-1SVCXPRT\s0 *xprt; +xdrproc_t outproc; +char *out; +.fi +.ft R +.IP +Called by an +.SM RPC +service's dispatch routine to send the results of a +remote procedure call.  The parameter +.I xprt +is the request's associated transport handle; +.I outproc +is the +.SM XDR +routine which is used to encode the results; and +.I out +is the address of the results. +This routine returns one if it succeeds, zero otherwise. +.br +.if t .ne 7 +.LP +.ft B +.nf +.sp .5 +void +svc_unregister(prognum, versnum) +u_long prognum, versnum; +.fi +.ft R +.IP +Remove all mapping of the double +.RI [ prognum , versnum ] +to dispatch routines, and of the triple +.RI [ prognum , versnum , *\fR] +to port number. +.br +.if t .ne 9 +.LP +.ft B +.nf +.sp .5 +void +svcerr_auth(xprt, why) +\s-1SVCXPRT\s0 *xprt; +enum auth_stat why; +.fi +.ft R +.IP +Called by a service dispatch routine that refuses to perform +a remote procedure call due to an authentication error. +.br +.if t .ne 7 +.LP +.ft B +.nf +.sp .5 +void +svcerr_decode(xprt) +\s-1SVCXPRT\s0 *xprt; +.fi +.ft R +.IP +Called by a service dispatch routine that cannot successfully +decode its parameters. See also +.BR svc_getargs(\|) . +.br +.if t .ne 7 +.LP +.ft B +.nf +.sp .5 +void +svcerr_noproc(xprt) +\s-1SVCXPRT\s0 *xprt; +.fi +.ft R +.IP +Called by a service dispatch routine that does not implement +the procedure number that the caller requests. +.br +.if t .ne 7 +.LP +.ft B +.nf +.sp .5 +void +svcerr_noprog(xprt) +\s-1SVCXPRT\s0 *xprt; +.fi +.ft R +.IP +Called when the desired program is not registered with the +.SM RPC +package. Service implementors usually do not need this routine. +.br +.if t .ne 7 +.LP +.ft B +.nf +.sp .5 +void +svcerr_progvers(xprt) +\s-1SVCXPRT\s0 *xprt; +.fi +.ft R +.IP +Called when the desired version of a program is not registered +with the +.SM RPC +package. Service implementors usually do not need this routine. +.br +.if t .ne 7 +.LP +.ft B +.nf +.sp .5 +void +svcerr_systemerr(xprt) +\s-1SVCXPRT\s0 *xprt; +.fi +.ft R +.IP +Called by a service dispatch routine when it detects a system +error +not covered by any particular protocol. +For example, if a service can no longer allocate storage, +it may call this routine. +.br +.if t .ne 8 +.LP +.ft B +.nf +.sp .5 +void +svcerr_weakauth(xprt) +\s-1SVCXPRT\s0 *xprt; +.fi +.ft R +.IP +Called by a service dispatch routine that refuses to perform +a remote procedure call due to insufficient +authentication parameters.  The routine calls +.BR "svcerr_auth(xprt, \s-1AUTH_TOOWEAK\s0)" . +.br +.if t .ne 11 +.LP +.ft B +.nf +.sp .5 +\s-1SVCXPRT\s0 * +svcraw_create(\|) +.fi +.ft R +.IP +This routine creates a toy +.SM RPC +service transport, to which it returns a pointer.  The +transport +is really a buffer within the process's address space, +so the corresponding +.SM RPC +client should live in the same +address space; +see +.BR clntraw_create(\|) . +This routine allows simulation of +.SM RPC +and acquisition of +.SM RPC +overheads (such as round trip times), without any kernel +interference. +This routine returns +.SM NULL +if it fails. +.br +.if t .ne 11 +.LP +.ft B +.nf +.sp .5 +\s-1SVCXPRT\s0 * +svctcp_create(sock, send_buf_size, recv_buf_size) +int sock; +u_int send_buf_size, recv_buf_size; +.fi +.ft R +.IP +This routine creates a +.SM TCP/IP\s0-based +.SM RPC +service transport, to which it returns a pointer. +The transport is associated with the socket +.IR sock , +which may be +.BR \s-1RPC_ANYSOCK\s0 , +in which case a new socket is created. +If the socket is not bound to a local +.SM TCP +port, then this routine binds it to an arbitrary port.  Upon +completion, +\fB\%xprt\->xp_sock\fR +is the transport's socket descriptor, and +\fB\%xprt\->xp_port\fR +is the transport's port number. +This routine returns +.SM NULL +if it fails. Since +.SM TCP\s0-based +.SM RPC +uses buffered +.SM I/O , +users may specify the size of buffers; values of zero +choose suitable defaults. +.br +.if t .ne 11 +.LP +.ft B +.nf +.sp .5 +\s-1SVCXPRT\s0 * +svcfd_create(fd, sendsize, recvsize) +int fd; +u_int sendsize; +u_int recvsize; +.fi +.ft R +.IP +Create a service on top of any open descriptor. Typically, +this +descriptor is a connected socket for a stream protocol such +as +.SM TCP\s0. +.I sendsize +and +.I recvsize +indicate sizes for the send and receive buffers.  If they are +zero, a reasonable default is chosen. +.br +.if t .ne 10 +.LP +.ft B +.nf +.sp .5 +\s-1SVCXPRT\s0 * +svcudp_bufcreate(sock, sendsize, recosize) +int sock; +.fi +.ft R +.IP +This routine creates a +.SM UDP/IP\s0-based +.SM RPC +service transport, to which it returns a pointer. +The transport is associated with the socket +.IR sock , +which may be +.B \s-1RPC_ANYSOCK\s0 , +in which case a new socket is created. +If the socket is not bound to a local +.SM UDP +port, then this routine binds it to an arbitrary port. Upon +completion, +\fB\%xprt\->xp_sock\fR +is the transport's socket descriptor, and +\fB\%xprt\->xp_port\fR +is the transport's port number. +This routine returns +.SM NULL +if it fails. +.IP +This allows the user to specify the maximun packet size for sending and  +receiving +.SM UDP\s0-based +.SM RPC messages. +.br +.if t .ne 7 +.LP +.ft B +.nf +.sp .5 +xdr_accepted_reply(xdrs, ar) +\s-1XDR\s0 *xdrs; +struct accepted_reply *ar; +.fi +.ft R +.IP +Used for encoding +.SM RPC +reply messages. This routine is useful for users who +wish to generate +\s-1RPC\s0-style +messages without using the +.SM RPC +package. +.br +.if t .ne 7 +.LP +.ft B +.nf +.sp .5 +xdr_authunix_parms(xdrs, aupp) +\s-1XDR\s0 *xdrs; +struct authunix_parms *aupp; +.fi +.ft R +.IP +Used for describing +.SM UNIX +credentials. This routine is useful for users +who wish to generate these credentials without using the +.SM RPC +authentication package. +.br +.if t .ne 7 +.LP +.ft B +.nf +.sp .5 +void +xdr_callhdr(xdrs, chdr) +\s-1XDR\s0 *xdrs; +struct rpc_msg *chdr; +.fi +.ft R +.IP +Used for describing +.SM RPC +call header messages. +This routine is useful for users who wish to generate +.SM RPC\s0-style +messages without using the +.SM RPC +package. +.br +.if t .ne 7 +.LP +.ft B +.nf +.sp .5 +xdr_callmsg(xdrs, cmsg) +\s-1XDR\s0 *xdrs; +struct rpc_msg *cmsg; +.fi +.ft R +.IP +Used for describing +.SM RPC +call messages. +This routine is useful for users who wish to generate +.SM RPC\s0-style +messages without using the +.SM RPC +package. +.br +.if t .ne 7 +.LP +.ft B +.nf +.sp .5 +xdr_opaque_auth(xdrs, ap) +\s-1XDR\s0 *xdrs; +struct opaque_auth *ap; +.fi +.ft R +.IP +Used for describing +.SM RPC +authentication information messages. +This routine is useful for users who wish to generate +.SM RPC\s0-style +messages without using the +.SM RPC +package. +.br +.if t .ne 7 +.LP +.ft B +.nf +.sp .5 +xdr_pmap(xdrs, regs) +\s-1XDR\s0 *xdrs; +struct pmap *regs; +.fi +.ft R +.IP +Used for describing parameters to various +.B portmap +procedures, externally. +This routine is useful for users who wish to generate +these parameters without using the +.B pmap +interface. +.br +.if t .ne 7 +.LP +.ft B +.nf +.sp .5 +xdr_pmaplist(xdrs, rp) +\s-1XDR\s0 *xdrs; +struct pmaplist **rp; +.fi +.ft R +.IP +Used for describing a list of port mappings, externally. +This routine is useful for users who wish to generate +these parameters without using the +.B pmap +interface. +.br +.if t .ne 7 +.LP +.ft B +.nf +.sp .5 +xdr_rejected_reply(xdrs, rr) +\s-1XDR\s0 *xdrs; +struct rejected_reply *rr; +.fi +.ft R +.IP +Used for describing +.SM RPC +reply messages. +This routine is useful for users who wish to generate +.SM RPC\s0-style +messages without using the +.SM RPC +package. +.br +.if t .ne 8 +.LP +.ft B +.nf +.sp .5 +xdr_replymsg(xdrs, rmsg) +\s-1XDR\s0 *xdrs; +struct rpc_msg *rmsg; +.fi +.ft R +.IP +Used for describing +.SM RPC +reply messages. +This routine is useful for users who wish to generate +.SM RPC +style messages without using the +.SM RPC +package. +.br +.if t .ne 8 +.LP +.ft B +.nf +.sp .5 +void +xprt_register(xprt) +\s-1SVCXPRT\s0 *xprt; +.fi +.ft R +.IP +After +.SM RPC +service transport handles are created, +they should register themselves with the +.SM RPC +service package. +This routine modifies the global variable +.BR svc_fds(\|) . +Service implementors usually do not need this routine. +.br +.if t .ne 8 +.LP +.ft B +.nf +.sp .5 +void +xprt_unregister(xprt) +\s-1SVCXPRT\s0 *xprt; +.fi +.ft R +.IP +Before an +.SM RPC +service transport handle is destroyed, +it should unregister itself with the +.SM RPC +service package. +This routine modifies the global variable +.BR svc_fds(\|) . +Service implementors usually do not need this routine. +.SH SEE ALSO +.BR rpc_secure (3N), +.BR xdr (3N) +.br +The following manuals: +.RS +.ft I +Remote Procedure Calls: Protocol Specification +.br +Remote Procedure Call Programming Guide +.br +rpcgen Programming Guide +.br +.ft R +.RE +.IR "\s-1RPC\s0: Remote Procedure Call Protocol Specification" , +.SM RFC1050, Sun Microsystems, Inc., +.SM USC-ISI\s0. + diff --git a/lib/librpc/man/man3/xdr.3n b/lib/librpc/man/man3/xdr.3n new file mode 100644 index 000000000000..b656ea804da8 --- /dev/null +++ b/lib/librpc/man/man3/xdr.3n @@ -0,0 +1,823 @@ +.\" @(#)xdr.3n	2.2 88/08/03 4.0 RPCSRC; from 1.16 88/03/14 SMI +.TH XDR 3N "16 February 1988" +.SH NAME +xdr \- library routines for external data representation +.SH SYNOPSIS AND DESCRIPTION +.LP +These routines allow C programmers to describe +arbitrary data structures in a machine-independent fashion. +Data for remote procedure calls are transmitted using these +routines. +.LP +.ft B +.nf +.sp .5 +xdr_array(xdrs, arrp, sizep, maxsize, elsize, elproc) +\s-1XDR\s0 *xdrs; +char **arrp; +u_int *sizep, maxsize, elsize; +xdrproc_t elproc; +.fi +.ft R +.IP +A filter primitive that translates between variable-length +arrays +and their corresponding external representations. The +parameter +.I arrp +is the address of the pointer to the array, while +.I sizep +is the address of the element count of the array; +this element count cannot exceed +.IR maxsize . +The parameter +.I elsize +is the +.I sizeof +each of the array's elements, and +.I elproc +is an +.SM XDR +filter that translates between +the array elements' C form, and their external +representation. +This routine returns one if it succeeds, zero otherwise. +.br +.if t .ne 8 +.LP +.ft B +.nf +.sp .5 +xdr_bool(xdrs, bp) +\s-1XDR\s0 *xdrs; +bool_t *bp; +.fi +.ft R +.IP +A filter primitive that translates between booleans (C +integers) +and their external representations. When encoding data, this +filter produces values of either one or zero. +This routine returns one if it succeeds, zero otherwise. +.br +.if t .ne 10 +.LP +.ft B +.nf +.sp .5 +xdr_bytes(xdrs, sp, sizep, maxsize) +\s-1XDR\s0 *xdrs; +char **sp; +u_int *sizep, maxsize; +.fi +.ft R +.IP +A filter primitive that translates between counted byte +strings and their external representations. +The parameter +.I sp +is the address of the string pointer. The length of the +string is located at address +.IR sizep ; +strings cannot be longer than +.IR maxsize . +This routine returns one if it succeeds, zero otherwise. +.br +.if t .ne 7 +.LP +.ft B +.nf +.sp .5 +xdr_char(xdrs, cp) +\s-1XDR\s0 *xdrs; +char *cp; +.fi +.ft R +.IP +A filter primitive that translates between C characters +and their external representations. +This routine returns one if it succeeds, zero otherwise. +Note: encoded characters are not packed, and occupy 4 bytes +each. For arrays of characters, it is worthwhile to +consider +.BR xdr_bytes(\|) , +.B xdr_opaque(\|) +or +.BR xdr_string(\|) . +.br +.if t .ne 8 +.LP +.ft B +.nf +.sp .5 +void +xdr_destroy(xdrs) +\s-1XDR\s0 *xdrs; +.fi +.ft R +.IP +A macro that invokes the destroy routine associated with the +.SM XDR +stream, +.IR xdrs . +Destruction usually involves freeing private data structures +associated with the stream.  Using +.I xdrs +after invoking +.B xdr_destroy(\|) +is undefined. +.br +.if t .ne 7 +.LP +.ft B +.nf +.sp .5 +xdr_double(xdrs, dp) +\s-1XDR\s0 *xdrs; +double *dp; +.fi +.ft R +.IP +A filter primitive that translates between C +.B double +precision numbers and their external representations. +This routine returns one if it succeeds, zero otherwise. +.br +.if t .ne 7 +.LP +.ft B +.nf +.sp .5 +xdr_enum(xdrs, ep) +\s-1XDR\s0 *xdrs; +enum_t *ep; +.fi +.ft R +.IP +A filter primitive that translates between C +.BR enum s +(actually integers) and their external representations. +This routine returns one if it succeeds, zero otherwise. +.br +.if t .ne 8 +.LP +.ft B +.nf +.sp .5 +xdr_float(xdrs, fp) +\s-1XDR\s0 *xdrs; +float *fp; +.fi +.ft R +.IP +A filter primitive that translates between C +.BR float s +and their external representations. +This routine returns one if it succeeds, zero otherwise. +.br +.if t .ne 9 +.LP +.ft B +.nf +.sp .5 +void +xdr_free(proc, objp) +xdrproc_t proc; +char *objp; +.fi +.ft R +.IP +Generic freeing routine. The first argument is the +.SM XDR +routine for the object being freed. The second argument +is a pointer to the object itself. Note: the pointer passed +to this routine is +.I not +freed, but what it points to +.I is +freed (recursively). +.br +.if t .ne 8 +.LP +.ft B +.nf +.sp .5 +u_int +xdr_getpos(xdrs) +\s-1XDR\s0 *xdrs; +.fi +.ft R +.IP +A macro that invokes the get-position routine +associated with the +.SM XDR +stream, +.IR xdrs . +The routine returns an unsigned integer, +which indicates the position of the +.SM XDR +byte stream. +A desirable feature of +.SM XDR +streams is that simple arithmetic works with this number, +although the +.SM XDR +stream instances need not guarantee this. +.br +.if t .ne 4 +.LP +.ft B +.nf +.sp .5 +.br +long * +xdr_inline(xdrs, len) +\s-1XDR\s0 *xdrs; +int len; +.fi +.ft R +.IP +A macro that invokes the in-line routine associated with the +.SM XDR +stream, +.IR xdrs . +The routine returns a pointer +to a contiguous piece of the stream's buffer; +.I len +is the byte length of the desired buffer. +Note: pointer is cast to +.BR "long *" . +.IP +Warning: +.B xdr_inline(\|) +may return +.SM NULL +(0) +if it cannot allocate a contiguous piece of a buffer. +Therefore the behavior may vary among stream instances; +it exists for the sake of efficiency. +.br +.if t .ne 7 +.LP +.ft B +.nf +.sp .5 +xdr_int(xdrs, ip) +\s-1XDR\s0 *xdrs; +int *ip; +.fi +.ft R +.IP +A filter primitive that translates between C integers +and their external representations. +This routine returns one if it succeeds, zero otherwise. +.br +.if t .ne 7 +.LP +.ft B +.nf +.sp .5 +xdr_long(xdrs, lp) +\s-1XDR\s0 *xdrs; +long *lp; +.fi +.ft R +.IP +A filter primitive that translates between C +.B long +integers and their external representations. +This routine returns one if it succeeds, zero otherwise. +.br +.if t .ne 12 +.LP +.ft B +.nf +.sp .5 +void +xdrmem_create(xdrs, addr, size, op) +\s-1XDR\s0 *xdrs; +char *addr; +u_int size; +enum xdr_op op; +.fi +.ft R +.IP +This routine initializes the +.SM XDR +stream object pointed to by +.IR xdrs . +The stream's data is written to, or read from, +a chunk of memory at location +.I addr +whose length is no more than +.I size +bytes long.  The +.I op +determines the direction of the +.SM XDR +stream +(either +.BR \s-1XDR_ENCODE\s0 , +.BR \s-1XDR_DECODE\s0 , +or +.BR \s-1XDR_FREE\s0 ). +.br +.if t .ne 10 +.LP +.ft B +.nf +.sp .5 +xdr_opaque(xdrs, cp, cnt) +\s-1XDR\s0 *xdrs; +char *cp; +u_int cnt; +.fi +.ft R +.IP +A filter primitive that translates between fixed size opaque +data +and its external representation. +The parameter +.I cp +is the address of the opaque object, and +.I cnt +is its size in bytes. +This routine returns one if it succeeds, zero otherwise. +.br +.if t .ne 10 +.LP +.ft B +.nf +.sp .5 +xdr_pointer(xdrs, objpp, objsize, xdrobj) +\s-1XDR\s0 *xdrs; +char **objpp; +u_int objsize; +xdrproc_t xdrobj; +.fi +.ft R +.IP +Like +.B xdr_reference(\|) +execpt that it serializes +.SM NULL +pointers, whereas +.B xdr_reference(\|) +does not.  Thus, +.B xdr_pointer(\|) +can represent +recursive data structures, such as binary trees or +linked lists. +.br +.if t .ne 15 +.LP +.ft B +.nf +.sp .5 +void +xdrrec_create(xdrs, sendsize, recvsize, handle, readit, writeit) +\s-1XDR\s0 *xdrs; +u_int sendsize, recvsize; +char *handle; +int (*readit) (\|), (*writeit) (\|); +.fi +.ft R +.IP +This routine initializes the +.SM XDR +stream object pointed to by +.IR xdrs . +The stream's data is written to a buffer of size +.IR sendsize ; +a value of zero indicates the system should use a suitable +default. The stream's data is read from a buffer of size +.IR recvsize ; +it too can be set to a suitable default by passing a zero +value. +When a stream's output buffer is full, +.I writeit +is called.  Similarly, when a stream's input buffer is empty, +.I readit +is called.  The behavior of these two routines is similar to +the +system calls +.B read +and +.BR write , +except that +.I handle +is passed to the former routines as the first parameter. +Note: the +.SM XDR +stream's +.I op +field must be set by the caller. +.IP +Warning: this +.SM XDR +stream implements an intermediate record stream. +Therefore there are additional bytes in the stream +to provide record boundary information. +.br +.if t .ne 9 +.LP +.ft B +.nf +.sp .5 +xdrrec_endofrecord(xdrs, sendnow) +\s-1XDR\s0 *xdrs; +int sendnow; +.fi +.ft R +.IP +This routine can be invoked only on +streams created by +.BR xdrrec_create(\|) . +The data in the output buffer is marked as a completed +record, +and the output buffer is optionally written out if +.I sendnow +is non-zero. This routine returns one if it succeeds, zero +otherwise. +.br +.if t .ne 8 +.LP +.ft B +.nf +.sp .5 +xdrrec_eof(xdrs) +\s-1XDR\s0 *xdrs; +int empty; +.fi +.ft R +.IP +This routine can be invoked only on +streams created by +.BR xdrrec_create(\|) . +After consuming the rest of the current record in the stream, +this routine returns one if the stream has no more input, +zero otherwise. +.br +.if t .ne 3 +.LP +.ft B +.nf +.sp .5 +xdrrec_skiprecord(xdrs) +\s-1XDR\s0 *xdrs; +.fi +.ft R +.IP +This routine can be invoked only on +streams created by +.BR xdrrec_create(\|) . +It tells the +.SM XDR +implementation that the rest of the current record +in the stream's input buffer should be discarded. +This routine returns one if it succeeds, zero otherwise. +.br +.if t .ne 11 +.LP +.ft B +.nf +.sp .5 +xdr_reference(xdrs, pp, size, proc) +\s-1XDR\s0 *xdrs; +char **pp; +u_int size; +xdrproc_t proc; +.fi +.ft R +.IP +A primitive that provides pointer chasing within structures. +The parameter +.I pp +is the address of the pointer; +.I size +is the +.I sizeof +the structure that +.I *pp +points to; and +.I proc +is an +.SM XDR +procedure that filters the structure +between its C form and its external representation. +This routine returns one if it succeeds, zero otherwise. +.IP +Warning: this routine does not understand +.SM NULL +pointers. Use +.B xdr_pointer(\|) +instead. +.br +.if t .ne 10 +.LP +.ft B +.nf +.sp .5 +xdr_setpos(xdrs, pos) +\s-1XDR\s0 *xdrs; +u_int pos; +.fi +.ft R +.IP +A macro that invokes the set position routine associated with +the +.SM XDR +stream +.IR xdrs . +The parameter +.I pos +is a position value obtained from +.BR xdr_getpos(\|) . +This routine returns one if the +.SM XDR +stream could be repositioned, +and zero otherwise. +.IP +Warning: it is difficult to reposition some types of +.SM XDR +streams, so this routine may fail with one +type of stream and succeed with another. +.br +.if t .ne 8 +.LP +.ft B +.nf +.sp .5 +xdr_short(xdrs, sp) +\s-1XDR\s0 *xdrs; +short *sp; +.fi +.ft R +.IP +A filter primitive that translates between C +.B short +integers and their external representations. +This routine returns one if it succeeds, zero otherwise. +.br +.if t .ne 10 +.LP +.ft B +.nf +.sp .5 +void +xdrstdio_create(xdrs, file, op) +\s-1XDR\s0 *xdrs; +\s-1FILE\s0 *file; +enum xdr_op op; +.fi +.ft R +.IP +This routine initializes the +.SM XDR +stream object pointed to by +.IR xdrs . +The +.SM XDR +stream data is written to, or read from, the Standard +.B I/O +stream +.IR file . +The parameter +.I op +determines the direction of the +.SM XDR +stream (either +.BR \s-1XDR_ENCODE\s0 , +.BR \s-1XDR_DECODE\s0 , +or +.BR \s-1XDR_FREE\s0 ). +.IP +Warning: the destroy routine associated with such +.SM XDR +streams calls +.B fflush(\|) +on the +.I file +stream, but never +.BR fclose(\|) . +.br +.if t .ne 9 +.LP +.ft B +.nf +.sp .5 +xdr_string(xdrs, sp, maxsize) +\s-1XDR\s0 +*xdrs; +char **sp; +u_int maxsize; +.fi +.ft R +.IP +A filter primitive that translates between C strings and +their +corresponding external representations. +Strings cannot be longer than +.IR maxsize . +Note:  +.I sp +is the address of the string's pointer. +This routine returns one if it succeeds, zero otherwise. +.br +.if t .ne 8 +.LP +.ft B +.nf +.sp .5 +xdr_u_char(xdrs, ucp) +\s-1XDR\s0 *xdrs; +unsigned char *ucp; +.fi +.ft R +.IP +A filter primitive that translates between +.B unsigned +C characters and their external representations. +This routine returns one if it succeeds, zero otherwise. +.br +.if t .ne 9 +.LP +.ft B +.nf +.sp .5 +xdr_u_int(xdrs, up) +\s-1XDR\s0 *xdrs; +unsigned *up; +.fi +.ft R +.IP +A filter primitive that translates between C +.B unsigned +integers and their external representations. +This routine returns one if it succeeds, zero otherwise. +.br +.if t .ne 7 +.LP +.ft B +.nf +.sp .5 +xdr_u_long(xdrs, ulp) +\s-1XDR\s0 *xdrs; +unsigned long *ulp; +.fi +.ft R +.IP +A filter primitive that translates between C +.B "unsigned long" +integers and their external representations. +This routine returns one if it succeeds, zero otherwise. +.br +.if t .ne 7 +.LP +.ft B +.nf +.sp .5 +xdr_u_short(xdrs, usp) +\s-1XDR\s0 *xdrs; +unsigned short *usp; +.fi +.ft R +.IP +A filter primitive that translates between C +.B "unsigned short" +integers and their external representations. +This routine returns one if it succeeds, zero otherwise. +.br +.if t .ne 16 +.LP +.ft B +.nf +.sp .5 +xdr_union(xdrs, dscmp, unp, choices, dfault) +\s-1XDR\s0 *xdrs; +int *dscmp; +char *unp; +struct xdr_discrim *choices; +bool_t (*defaultarm) (\|);  /* may equal \s-1NULL\s0 */ +.fi +.ft R +.IP +A filter primitive that translates between a discriminated C +.B union +and its corresponding external representation. It first +translates the discriminant of the union located at +.IR dscmp . +This discriminant is always an +.BR enum_t . +Next the union located at +.I unp +is translated.  The parameter +.I choices +is a pointer to an array of +.B xdr_discrim(\|) +structures. Each structure contains an ordered pair of +.RI [ value , proc ]. +If the union's discriminant is equal to the associated +.IR value , +then the +.I proc +is called to translate the union.  The end of the +.B xdr_discrim(\|) +structure array is denoted by a routine of value +.SM NULL\s0. +If the discriminant is not found in the +.I choices +array, then the +.I defaultarm +procedure is called (if it is not +.SM NULL\s0). +Returns one if it succeeds, zero otherwise. +.br +.if t .ne 6 +.LP +.ft B +.nf +.sp .5 +xdr_vector(xdrs, arrp, size, elsize, elproc) +\s-1XDR\s0 *xdrs; +char *arrp; +u_int size, elsize; +xdrproc_t elproc; +.fi +.ft R +.IP +A filter primitive that translates between fixed-length +arrays +and their corresponding external representations.  The +parameter +.I arrp +is the address of the pointer to the array, while +.I size +is is the element count of the array.  The parameter +.I elsize +is the +.I sizeof +each of the array's elements, and +.I elproc +is an +.SM XDR +filter that translates between +the array elements' C form, and their external +representation. +This routine returns one if it succeeds, zero otherwise. +.br +.if t .ne 5 +.LP +.ft B +.nf +.sp .5 +xdr_void(\|) +.fi +.ft R +.IP +This routine always returns one. +It may be passed to +.SM RPC +routines that require a function parameter, +where nothing is to be done. +.br +.if t .ne 10 +.LP +.ft B +.nf +.sp .5 +xdr_wrapstring(xdrs, sp) +\s-1XDR\s0 *xdrs; +char **sp; +.fi +.ft R +.IP +A primitive that calls +.B "xdr_string(xdrs, sp,\s-1MAXUN.UNSIGNED\s0 );" +where +.B +.SM MAXUN.UNSIGNED +is the maximum value of an unsigned integer. +.B xdr_wrapstring(\|) +is handy because the +.SM RPC +package passes a maximum of two +.SM XDR +routines as parameters, and +.BR xdr_string(\|) , +one of the most frequently used primitives, requires three. +Returns one if it succeeds, zero otherwise. +.SH SEE ALSO +.BR rpc (3N) +.LP +The following manuals: +.RS +.ft I +eXternal Data Representation Standard: Protocol Specification +.br +eXternal Data Representation: Sun Technical Notes +.ft R +.br +.IR "\s-1XDR\s0: External Data Representation Standard" , +.SM RFC1014, Sun Microsystems, Inc., +.SM USC-ISI\s0. diff --git a/lib/librpc/man/man5/rpc.5 b/lib/librpc/man/man5/rpc.5 new file mode 100644 index 000000000000..324ecb153a83 --- /dev/null +++ b/lib/librpc/man/man5/rpc.5 @@ -0,0 +1,71 @@ +.\" @(#)rpc.5	2.2 88/08/03 4.0 RPCSRC; from 1.4 87/11/27 SMI; +.TH RPC 5  "26 September 1985" +.SH NAME +rpc \- rpc program number data base +.SH SYNOPSIS +.B /etc/rpc +.SH DESCRIPTION +The +.I rpc +file contains user readable names that +can be used in place of rpc program numbers. +Each line has the following information: +.HP 10 +name of server for the rpc program +.br +.ns +.HP 10 +rpc program number +.br +.ns +.HP 10 +aliases +.LP +Items are separated by any number of blanks and/or +tab characters. +A ``#'' indicates the beginning of a comment; characters up to the end of +the line are not interpreted by routines which search the file. +.LP +Here is an example of the \fI/etc/rpc\fP file from the Sun RPC Source +distribution. +.nf +.ta 1.5i +0.5i +1.0i +1.0i +# +# rpc 88/08/01 4.0 RPCSRC; from 1.12   88/02/07 SMI +# +portmapper		100000	portmap sunrpc +rstatd		100001	rstat rstat_svc rup perfmeter +rusersd		100002	rusers +nfs		100003	nfsprog +ypserv		100004	ypprog +mountd		100005	mount showmount +ypbind		100007 +walld		100008	rwall shutdown +yppasswdd		100009	yppasswd +etherstatd		100010	etherstat +rquotad		100011	rquotaprog quota rquota +sprayd		100012	spray +3270_mapper		100013 +rje_mapper		100014 +selection_svc		100015	selnsvc +database_svc		100016 +rexd		100017	rex +alis		100018 +sched		100019 +llockmgr		100020 +nlockmgr		100021 +x25.inr		100022 +statmon		100023 +status		100024 +bootparam		100026 +ypupdated		100028	ypupdate +keyserv		100029	keyserver +tfsd		100037  +nsed		100038 +nsemntd		100039 +.fi +.DT +.SH FILES +/etc/rpc +.SH "SEE ALSO" +getrpcent(3N) diff --git a/lib/librpc/man/man8/portmap.8c b/lib/librpc/man/man8/portmap.8c new file mode 100644 index 000000000000..862bd0518460 --- /dev/null +++ b/lib/librpc/man/man8/portmap.8c @@ -0,0 +1,53 @@ +.\" @(#)portmap.8c	2.2 88/08/03 4.0 RPCSRC; from 1.10 88/03/14 SMI +.TH PORTMAP 8C "9 September 1987" +.SH NAME +portmap \- DARPA port to RPC program number mapper +.SH SYNOPSIS +.B /usr/etc/rpc.portmap +.SH DESCRIPTION +.IX  "portmap command"  ""  "\fLportmap\fP \(em DARPA to RPC mapper" +.IX  DARPA "to RPC mapper \(em \fLportmap\fP" +.B portmap +is a server that converts +.SM RPC +program numbers into +.SM DARPA +protocol port numbers. +It must be running in order to make +.SM RPC +calls. +.LP +When an +.SM RPC +server is started, it will tell +.B portmap +what port number it is listening to, and what +.SM RPC +program numbers it is prepared to serve. +When a client wishes to make an +.SM RPC +call to a given program number, +it will first contact +.B portmap +on the server machine to determine +the port number where +.SM RPC +packets should be sent. +.LP +Normally, standard +.SM RPC +servers are started by +.BR inetd (8C), +so +.B portmap +must be started before +.B inetd +is invoked. +.SH "SEE ALSO" +.BR inetd.conf (5), +.BR rpcinfo (8), +.BR inetd (8) +.SH BUGS +If +.B portmap +crashes, all servers must be restarted. diff --git a/lib/librpc/man/man8/rpcinfo.8c b/lib/librpc/man/man8/rpcinfo.8c new file mode 100644 index 000000000000..2d0de97fd39e --- /dev/null +++ b/lib/librpc/man/man8/rpcinfo.8c @@ -0,0 +1,183 @@ +.\" @(#)rpcinfo.8c	2.2 88/08/03 4.0 RPCSRC; from 1.24 88/02/25 SMI +.TH RPCINFO 8C "17 December 1987" +.SH NAME +rpcinfo \- report RPC information +.SH SYNOPSIS +.B "rpcinfo \-p" +[ +.I host +] +.LP +.B "rpcinfo" +[ +.B \-n +.I portnum +] +.B \-u +.I host +.I program +[ +.I version +] +.LP +.B "rpcinfo" +[ +.B \-n +.I portnum +] +.B \-t +.I host +.I program +[ +.I version +] +.LP +.B "rpcinfo \-b" +.I program +.I version +.LP +.B "rpcinfo \-d" +.I program +.I version +.SH DESCRIPTION +.B rpcinfo +makes an +.SM RPC +call to an +.SM RPC +server and reports what it finds. +.SH OPTIONS +.TP +.B \-p +Probe the portmapper on +.IR host , +and print a list of all registered +.SM RPC +programs.  If +.I host +is not specified, it defaults to the value returned by +.BR hostname (1). +.TP +.B \-u +Make an +.SM RPC +call to procedure 0 of +.I program +on the specified +.I host +using +.SM UDP\s0, +and report whether a response was received. +.TP +.B \-t +Make an +.SM RPC +call to procedure 0 of +.I program +on the specified +.I host +using +.SM TCP\s0, +and report whether a response was received. +.TP +.B \-n +Use +.I portnum +as the port number for the +.I \-t +and +.I \-u +options instead of the port number given by the portmapper. +.TP +.B \-b +Make an +.SM RPC +broadcast to procedure 0 of the specified +.I program +and +.I version +using +.SM UDP +and report all hosts that respond. +.TP +.B \-d +Delete registration for the +.SM RPC +service of the specified +.I program +and +.IR version . +This option can be exercised only by the super-user. +.LP +The +.I program +argument can be either a name or a number. +.LP +If a +.I version +is specified, +.B rpcinfo +attempts to call that version of the specified +.IR program . +Otherwise, +.B rpcinfo +attempts to find all the registered version +numbers for the specified +.I program +by calling version 0 (which is presumed not +to exist; if it does exist, +.B rpcinfo +attempts to obtain this information by calling +an extremely high version +number instead) and attempts to call each registered version. +Note: the version number is required for +.B \-b +and +.B \-d +options. +.SH EXAMPLES +To show all of the +.SM RPC +services registered on the local machine use: +.IP +.B example% rpcinfo -p +.LP +To show all of the +.SM RPC +services registered on the machine named +.B klaxon +use: +.IP +.B example% rpcinfo -p klaxon +.LP +To show all machines on the local net that are running the Yellow Pages +service use: +.IP +.B "example% rpcinfo -b ypserv 'version' | uniq" +.LP +where 'version' is the current Yellow Pages version obtained from the +results of the +.B \-p +switch above. +.LP +To delete the registration for version 1 of the +.B walld +service use: +.IP +.B example% rpcinfo -d walld 1 +.SH "SEE ALSO" +.BR rpc (5), +.BR portmap (8C) +.LP +.I "\s-1RPC\s0 Programming Guide" +.SH BUGS +In releases prior to Sun\s-1OS\s0 +3.0, the Network File System (\s-1NFS\s0) did not +register itself with the +portmapper; +.B rpcinfo +cannot be used to make +.SM RPC +calls to the +.SM NFS +server on hosts running such releases. diff --git a/lib/librpc/man/man8/rstat_svc.8c b/lib/librpc/man/man8/rstat_svc.8c new file mode 100644 index 000000000000..a10b71dbacad --- /dev/null +++ b/lib/librpc/man/man8/rstat_svc.8c @@ -0,0 +1,21 @@ +.\" @(#)rstat_svc.8c	2.2 88/08/03 4.0 RPCSRC; from 1.10 87/09/09 SMI +.TH RSTAT_SVC 8C "24 November 1987" +.SH NAME +rstat_svc \- kernel statistics server +.SH SYNOPSIS +.B /etc/rstat_svc +.SH DESCRIPTION +.LP +.B rstat_svc +is a server which returns performance statistics +obtained from the kernel. +These statistics are graphically displayed by the Sun Microsystems program, +.BR perfmeter (1). +The +.B rstat_svc +daemon is normally invoked at boot time through /etc/rc.local. +.PP +.B rstat_svc +uses an RPC protocol defined in /usr/include/rpcsvc/rstat.x. +.SH "SEE ALSO" +.BR rstat (1), diff --git a/lib/librpc/rpc/auth.h b/lib/librpc/rpc/auth.h new file mode 100644 index 000000000000..a823ddd2ba85 --- /dev/null +++ b/lib/librpc/rpc/auth.h @@ -0,0 +1,166 @@ +/* @(#)auth.h	2.3 88/08/07 4.0 RPCSRC; from 1.17 88/02/08 SMI */ +/* + * Sun RPC is a product of Sun Microsystems, Inc. and is provided for + * unrestricted use provided that this legend is included on all tape + * media and as a part of the software program in whole or part.  Users + * may copy or modify Sun RPC without charge, but are not authorized + * to license or distribute it to anyone else except as part of a product or + * program developed by the user. + *  + * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE + * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR + * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. + *  + * Sun RPC is provided with no support and without any obligation on the + * part of Sun Microsystems, Inc. to assist in its use, correction, + * modification or enhancement. + *  + * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE + * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC + * OR ANY PART THEREOF. + *  + * In no event will Sun Microsystems, Inc. be liable for any lost revenue + * or profits or other special, indirect and consequential damages, even if + * Sun has been advised of the possibility of such damages. + *  + * Sun Microsystems, Inc. + * 2550 Garcia Avenue + * Mountain View, California  94043 + */ + +/* + * auth.h, Authentication interface. + * + * Copyright (C) 1984, Sun Microsystems, Inc. + * + * The data structures are completely opaque to the client.  The client + * is required to pass a AUTH * to routines that create rpc + * "sessions". + */ + + +#define MAX_AUTH_BYTES	400 +#define MAXNETNAMELEN	255	/* maximum length of network user's name */ + +/* + * Status returned from authentication check + */ +enum auth_stat { +	AUTH_OK=0, +	/* +	 * failed at remote end +	 */ +	AUTH_BADCRED=1,			/* bogus credentials (seal broken) */ +	AUTH_REJECTEDCRED=2,		/* client should begin new session */ +	AUTH_BADVERF=3,			/* bogus verifier (seal broken) */ +	AUTH_REJECTEDVERF=4,		/* verifier expired or was replayed */ +	AUTH_TOOWEAK=5,			/* rejected due to security reasons */ +	/* +	 * failed locally +	*/ +	AUTH_INVALIDRESP=6,		/* bogus response verifier */ +	AUTH_FAILED=7			/* some unknown reason */ +}; + +#if (mc68000 || sparc || vax || i386 || tahoe || luna68k || hp300 || mips) +typedef u_long u_int32;	/* 32-bit unsigned integers */ +#endif + +union des_block { +	struct { +		u_int32 high; +		u_int32 low; +	} key; +	char c[8]; +}; +typedef union des_block des_block; +extern bool_t xdr_des_block(); + +/* + * Authentication info.  Opaque to client. + */ +struct opaque_auth { +	enum_t	oa_flavor;		/* flavor of auth */ +	caddr_t	oa_base;		/* address of more auth stuff */ +	u_int	oa_length;		/* not to exceed MAX_AUTH_BYTES */ +}; + + +/* + * Auth handle, interface to client side authenticators. + */ +typedef struct { +	struct	opaque_auth	ah_cred; +	struct	opaque_auth	ah_verf; +	union	des_block	ah_key; +	struct auth_ops { +		void	(*ah_nextverf)(); +		int	(*ah_marshal)();	/* nextverf & serialize */ +		int	(*ah_validate)();	/* validate varifier */ +		int	(*ah_refresh)();	/* refresh credentials */ +		void	(*ah_destroy)();	/* destroy this structure */ +	} *ah_ops; +	caddr_t ah_private; +} AUTH; + + +/* + * Authentication ops. + * The ops and the auth handle provide the interface to the authenticators. + * + * AUTH	*auth; + * XDR	*xdrs; + * struct opaque_auth verf; + */ +#define AUTH_NEXTVERF(auth)		\ +		((*((auth)->ah_ops->ah_nextverf))(auth)) +#define auth_nextverf(auth)		\ +		((*((auth)->ah_ops->ah_nextverf))(auth)) + +#define AUTH_MARSHALL(auth, xdrs)	\ +		((*((auth)->ah_ops->ah_marshal))(auth, xdrs)) +#define auth_marshall(auth, xdrs)	\ +		((*((auth)->ah_ops->ah_marshal))(auth, xdrs)) + +#define AUTH_VALIDATE(auth, verfp)	\ +		((*((auth)->ah_ops->ah_validate))((auth), verfp)) +#define auth_validate(auth, verfp)	\ +		((*((auth)->ah_ops->ah_validate))((auth), verfp)) + +#define AUTH_REFRESH(auth)		\ +		((*((auth)->ah_ops->ah_refresh))(auth)) +#define auth_refresh(auth)		\ +		((*((auth)->ah_ops->ah_refresh))(auth)) + +#define AUTH_DESTROY(auth)		\ +		((*((auth)->ah_ops->ah_destroy))(auth)) +#define auth_destroy(auth)		\ +		((*((auth)->ah_ops->ah_destroy))(auth)) + + +extern struct opaque_auth _null_auth; + + +/* + * These are the various implementations of client side authenticators. + */ + +/* + * Unix style authentication + * AUTH *authunix_create(machname, uid, gid, len, aup_gids) + *	char *machname; + *	int uid; + *	int gid; + *	int len; + *	int *aup_gids; + */ +extern AUTH *authunix_create(); +extern AUTH *authunix_create_default();	/* takes no parameters */ +extern AUTH *authnone_create();		/* takes no parameters */ +extern AUTH *authdes_create(); + +#define AUTH_NONE	0		/* no authentication */ +#define	AUTH_NULL	0		/* backward compatibility */ +#define	AUTH_UNIX	1		/* unix style (uid, gids) */ +#define	AUTH_SHORT	2		/* short hand unix style */ +#define AUTH_DES	3		/* des style (encrypted timestamps) */ diff --git a/lib/librpc/rpc/auth_none.c b/lib/librpc/rpc/auth_none.c new file mode 100644 index 000000000000..630037fb47d3 --- /dev/null +++ b/lib/librpc/rpc/auth_none.c @@ -0,0 +1,133 @@ +/* @(#)auth_none.c	2.1 88/07/29 4.0 RPCSRC */ +/* + * Sun RPC is a product of Sun Microsystems, Inc. and is provided for + * unrestricted use provided that this legend is included on all tape + * media and as a part of the software program in whole or part.  Users + * may copy or modify Sun RPC without charge, but are not authorized + * to license or distribute it to anyone else except as part of a product or + * program developed by the user. + *  + * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE + * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR + * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. + *  + * Sun RPC is provided with no support and without any obligation on the + * part of Sun Microsystems, Inc. to assist in its use, correction, + * modification or enhancement. + *  + * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE + * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC + * OR ANY PART THEREOF. + *  + * In no event will Sun Microsystems, Inc. be liable for any lost revenue + * or profits or other special, indirect and consequential damages, even if + * Sun has been advised of the possibility of such damages. + *  + * Sun Microsystems, Inc. + * 2550 Garcia Avenue + * Mountain View, California  94043 + */ +#if !defined(lint) && defined(SCCSIDS) +static char sccsid[] = "@(#)auth_none.c 1.19 87/08/11 Copyr 1984 Sun Micro"; +#endif + +/* + * auth_none.c + * Creates a client authentication handle for passing "null"  + * credentials and verifiers to remote systems.  + *  + * Copyright (C) 1984, Sun Microsystems, Inc.  + */ + +#include <rpc/types.h> +#include <rpc/xdr.h> +#include <rpc/auth.h> +#define MAX_MARSHEL_SIZE 20 + +/* + * Authenticator operations routines + */ +static void	authnone_verf(); +static void	authnone_destroy(); +static bool_t	authnone_marshal(); +static bool_t	authnone_validate(); +static bool_t	authnone_refresh(); + +static struct auth_ops ops = { +	authnone_verf, +	authnone_marshal, +	authnone_validate, +	authnone_refresh, +	authnone_destroy +}; + +static struct authnone_private { +	AUTH	no_client; +	char	marshalled_client[MAX_MARSHEL_SIZE]; +	u_int	mcnt; +} *authnone_private; + +AUTH * +authnone_create() +{ +	register struct authnone_private *ap = authnone_private; +	XDR xdr_stream; +	register XDR *xdrs; + +	if (ap == 0) { +		ap = (struct authnone_private *)calloc(1, sizeof (*ap)); +		if (ap == 0) +			return (0); +		authnone_private = ap; +	} +	if (!ap->mcnt) { +		ap->no_client.ah_cred = ap->no_client.ah_verf = _null_auth; +		ap->no_client.ah_ops = &ops; +		xdrs = &xdr_stream; +		xdrmem_create(xdrs, ap->marshalled_client, (u_int)MAX_MARSHEL_SIZE, +		    XDR_ENCODE); +		(void)xdr_opaque_auth(xdrs, &ap->no_client.ah_cred); +		(void)xdr_opaque_auth(xdrs, &ap->no_client.ah_verf); +		ap->mcnt = XDR_GETPOS(xdrs); +		XDR_DESTROY(xdrs); +	} +	return (&ap->no_client); +} + +/*ARGSUSED*/ +static bool_t +authnone_marshal(client, xdrs) +	AUTH *client; +	XDR *xdrs; +{ +	register struct authnone_private *ap = authnone_private; + +	if (ap == 0) +		return (0); +	return ((*xdrs->x_ops->x_putbytes)(xdrs, +	    ap->marshalled_client, ap->mcnt)); +} + +static void  +authnone_verf() +{ +} + +static bool_t +authnone_validate() +{ + +	return (TRUE); +} + +static bool_t +authnone_refresh() +{ + +	return (FALSE); +} + +static void +authnone_destroy() +{ +} diff --git a/lib/librpc/rpc/auth_unix.c b/lib/librpc/rpc/auth_unix.c new file mode 100644 index 000000000000..d085d02648a6 --- /dev/null +++ b/lib/librpc/rpc/auth_unix.c @@ -0,0 +1,337 @@ +/* @(#)auth_unix.c	2.2 88/08/01 4.0 RPCSRC */ +/* + * Sun RPC is a product of Sun Microsystems, Inc. and is provided for + * unrestricted use provided that this legend is included on all tape + * media and as a part of the software program in whole or part.  Users + * may copy or modify Sun RPC without charge, but are not authorized + * to license or distribute it to anyone else except as part of a product or + * program developed by the user. + *  + * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE + * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR + * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. + *  + * Sun RPC is provided with no support and without any obligation on the + * part of Sun Microsystems, Inc. to assist in its use, correction, + * modification or enhancement. + * + * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE + * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC + * OR ANY PART THEREOF. + *  + * In no event will Sun Microsystems, Inc. be liable for any lost revenue + * or profits or other special, indirect and consequential damages, even if + * Sun has been advised of the possibility of such damages. + *  + * Sun Microsystems, Inc. + * 2550 Garcia Avenue + * Mountain View, California  94043 + */ +#if !defined(lint) && defined(SCCSIDS) +static char sccsid[] = "@(#)auth_unix.c 1.19 87/08/11 Copyr 1984 Sun Micro"; +#endif + +/* + * auth_unix.c, Implements UNIX style authentication parameters.  + *   + * Copyright (C) 1984, Sun Microsystems, Inc. + * + * The system is very weak.  The client uses no encryption for it's + * credentials and only sends null verifiers.  The server sends backs + * null verifiers or optionally a verifier that suggests a new short hand + * for the credentials. + * + */ + +#include <stdio.h> + +#include <rpc/types.h> +#include <rpc/xdr.h> +#include <rpc/auth.h> +#include <rpc/auth_unix.h> + +/* + * Unix authenticator operations vector + */ +static void	authunix_nextverf(); +static bool_t	authunix_marshal(); +static bool_t	authunix_validate(); +static bool_t	authunix_refresh(); +static void	authunix_destroy(); + +static struct auth_ops auth_unix_ops = { +	authunix_nextverf, +	authunix_marshal, +	authunix_validate, +	authunix_refresh, +	authunix_destroy +}; + +/* + * This struct is pointed to by the ah_private field of an auth_handle. + */ +struct audata { +	struct opaque_auth	au_origcred;	/* original credentials */ +	struct opaque_auth	au_shcred;	/* short hand cred */ +	u_long			au_shfaults;	/* short hand cache faults */ +	char			au_marshed[MAX_AUTH_BYTES]; +	u_int			au_mpos;	/* xdr pos at end of marshed */ +}; +#define	AUTH_PRIVATE(auth)	((struct audata *)auth->ah_private) + +static bool_t marshal_new_auth(); + + +/* + * Create a unix style authenticator. + * Returns an auth handle with the given stuff in it. + */ +AUTH * +authunix_create(machname, uid, gid, len, aup_gids) +	char *machname; +	int uid; +	int gid; +	register int len; +	int *aup_gids; +{ +	struct authunix_parms aup; +	char mymem[MAX_AUTH_BYTES]; +	struct timeval now; +	XDR xdrs; +	register AUTH *auth; +	register struct audata *au; + +	/* +	 * Allocate and set up auth handle +	 */ +	auth = (AUTH *)mem_alloc(sizeof(*auth)); +#ifndef KERNEL +	if (auth == NULL) { +		(void)fprintf(stderr, "authunix_create: out of memory\n"); +		return (NULL); +	} +#endif +	au = (struct audata *)mem_alloc(sizeof(*au)); +#ifndef KERNEL +	if (au == NULL) { +		(void)fprintf(stderr, "authunix_create: out of memory\n"); +		return (NULL); +	} +#endif +	auth->ah_ops = &auth_unix_ops; +	auth->ah_private = (caddr_t)au; +	auth->ah_verf = au->au_shcred = _null_auth; +	au->au_shfaults = 0; + +	/* +	 * fill in param struct from the given params +	 */ +	(void)gettimeofday(&now,  (struct timezone *)0); +	aup.aup_time = now.tv_sec; +	aup.aup_machname = machname; +	aup.aup_uid = uid; +	aup.aup_gid = gid; +	aup.aup_len = (u_int)len; +	aup.aup_gids = aup_gids; + +	/* +	 * Serialize the parameters into origcred +	 */ +	xdrmem_create(&xdrs, mymem, MAX_AUTH_BYTES, XDR_ENCODE); +	if (! xdr_authunix_parms(&xdrs, &aup))  +		abort(); +	au->au_origcred.oa_length = len = XDR_GETPOS(&xdrs); +	au->au_origcred.oa_flavor = AUTH_UNIX; +#ifdef KERNEL +	au->au_origcred.oa_base = mem_alloc((u_int) len); +#else +	if ((au->au_origcred.oa_base = mem_alloc((u_int) len)) == NULL) { +		(void)fprintf(stderr, "authunix_create: out of memory\n"); +		return (NULL); +	} +#endif +	bcopy(mymem, au->au_origcred.oa_base, (u_int)len); + +	/* +	 * set auth handle to reflect new cred. +	 */ +	auth->ah_cred = au->au_origcred; +	marshal_new_auth(auth); +	return (auth); +} + +/* + * Some servers will refuse mounts if the group list is larger + * than it expects (like 8). This allows the application to set + * the maximum size of the group list that will be sent. + */ + +static maxgrplist = NGRPS; + +set_rpc_maxgrouplist(num) +	int num; +{ + +	if (num < NGRPS) +		maxgrplist = num; +} + +/* + * Returns an auth handle with parameters determined by doing lots of + * syscalls. + */ +AUTH * +authunix_create_default() +{ +	register int len; +	char machname[MAX_MACHINE_NAME + 1]; +	register int uid; +	register int gid; +	int gids[NGRPS]; + +	if (gethostname(machname, MAX_MACHINE_NAME) == -1) +		abort(); +	machname[MAX_MACHINE_NAME] = 0; +	uid = geteuid(); +	gid = getegid(); +	if ((len = getgroups(NGRPS, gids)) < 0) +		abort(); +	if (len > maxgrplist) +		len = maxgrplist; +	return (authunix_create(machname, uid, gid, len, gids)); +} + +/* + * authunix operations + */ + +static void +authunix_nextverf(auth) +	AUTH *auth; +{ +	/* no action necessary */ +} + +static bool_t +authunix_marshal(auth, xdrs) +	AUTH *auth; +	XDR *xdrs; +{ +	register struct audata *au = AUTH_PRIVATE(auth); + +	return (XDR_PUTBYTES(xdrs, au->au_marshed, au->au_mpos)); +} + +static bool_t +authunix_validate(auth, verf) +	register AUTH *auth; +	struct opaque_auth verf; +{ +	register struct audata *au; +	XDR xdrs; + +	if (verf.oa_flavor == AUTH_SHORT) { +		au = AUTH_PRIVATE(auth); +		xdrmem_create(&xdrs, verf.oa_base, verf.oa_length, XDR_DECODE); + +		if (au->au_shcred.oa_base != NULL) { +			mem_free(au->au_shcred.oa_base, +			    au->au_shcred.oa_length); +			au->au_shcred.oa_base = NULL; +		} +		if (xdr_opaque_auth(&xdrs, &au->au_shcred)) { +			auth->ah_cred = au->au_shcred; +		} else { +			xdrs.x_op = XDR_FREE; +			(void)xdr_opaque_auth(&xdrs, &au->au_shcred); +			au->au_shcred.oa_base = NULL; +			auth->ah_cred = au->au_origcred; +		} +		marshal_new_auth(auth); +	} +	return (TRUE); +} + +static bool_t +authunix_refresh(auth) +	register AUTH *auth; +{ +	register struct audata *au = AUTH_PRIVATE(auth); +	struct authunix_parms aup; +	struct timeval now; +	XDR xdrs; +	register int stat; + +	if (auth->ah_cred.oa_base == au->au_origcred.oa_base) { +		/* there is no hope.  Punt */ +		return (FALSE); +	} +	au->au_shfaults ++; + +	/* first deserialize the creds back into a struct authunix_parms */ +	aup.aup_machname = NULL; +	aup.aup_gids = (int *)NULL; +	xdrmem_create(&xdrs, au->au_origcred.oa_base, +	    au->au_origcred.oa_length, XDR_DECODE); +	stat = xdr_authunix_parms(&xdrs, &aup); +	if (! stat)  +		goto done; + +	/* update the time and serialize in place */ +	(void)gettimeofday(&now, (struct timezone *)0); +	aup.aup_time = now.tv_sec; +	xdrs.x_op = XDR_ENCODE; +	XDR_SETPOS(&xdrs, 0); +	stat = xdr_authunix_parms(&xdrs, &aup); +	if (! stat) +		goto done; +	auth->ah_cred = au->au_origcred; +	marshal_new_auth(auth); +done: +	/* free the struct authunix_parms created by deserializing */ +	xdrs.x_op = XDR_FREE; +	(void)xdr_authunix_parms(&xdrs, &aup); +	XDR_DESTROY(&xdrs); +	return (stat); +} + +static void +authunix_destroy(auth) +	register AUTH *auth; +{ +	register struct audata *au = AUTH_PRIVATE(auth); + +	mem_free(au->au_origcred.oa_base, au->au_origcred.oa_length); + +	if (au->au_shcred.oa_base != NULL) +		mem_free(au->au_shcred.oa_base, au->au_shcred.oa_length); + +	mem_free(auth->ah_private, sizeof(struct audata)); + +	if (auth->ah_verf.oa_base != NULL) +		mem_free(auth->ah_verf.oa_base, auth->ah_verf.oa_length); + +	mem_free((caddr_t)auth, sizeof(*auth)); +} + +/* + * Marshals (pre-serializes) an auth struct. + * sets private data, au_marshed and au_mpos + */ +static bool_t +marshal_new_auth(auth) +	register AUTH *auth; +{ +	XDR		xdr_stream; +	register XDR	*xdrs = &xdr_stream; +	register struct audata *au = AUTH_PRIVATE(auth); + +	xdrmem_create(xdrs, au->au_marshed, MAX_AUTH_BYTES, XDR_ENCODE); +	if ((! xdr_opaque_auth(xdrs, &(auth->ah_cred))) || +	    (! xdr_opaque_auth(xdrs, &(auth->ah_verf)))) { +		perror("auth_none.c - Fatal marshalling problem"); +	} else { +		au->au_mpos = XDR_GETPOS(xdrs); +	} +	XDR_DESTROY(xdrs); +} diff --git a/lib/librpc/rpc/auth_unix.h b/lib/librpc/rpc/auth_unix.h new file mode 100644 index 000000000000..705741e1393c --- /dev/null +++ b/lib/librpc/rpc/auth_unix.h @@ -0,0 +1,72 @@ +/* @(#)auth_unix.h	2.2 88/07/29 4.0 RPCSRC; from 1.8 88/02/08 SMI */ +/* + * Sun RPC is a product of Sun Microsystems, Inc. and is provided for + * unrestricted use provided that this legend is included on all tape + * media and as a part of the software program in whole or part.  Users + * may copy or modify Sun RPC without charge, but are not authorized + * to license or distribute it to anyone else except as part of a product or + * program developed by the user. + *  + * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE + * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR + * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. + *  + * Sun RPC is provided with no support and without any obligation on the + * part of Sun Microsystems, Inc. to assist in its use, correction, + * modification or enhancement. + *  + * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE + * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC + * OR ANY PART THEREOF. + *  + * In no event will Sun Microsystems, Inc. be liable for any lost revenue + * or profits or other special, indirect and consequential damages, even if + * Sun has been advised of the possibility of such damages. + *  + * Sun Microsystems, Inc. + * 2550 Garcia Avenue + * Mountain View, California  94043 + */ +/*      @(#)auth_unix.h 1.5 86/07/16 SMI      */ + +/* + * auth_unix.h, Protocol for UNIX style authentication parameters for RPC + * + * Copyright (C) 1984, Sun Microsystems, Inc. + */ + +/* + * The system is very weak.  The client uses no encryption for  it + * credentials and only sends null verifiers.  The server sends backs + * null verifiers or optionally a verifier that suggests a new short hand + * for the credentials. + */ + +/* The machine name is part of a credential; it may not exceed 255 bytes */ +#define MAX_MACHINE_NAME 255 + +/* gids compose part of a credential; there may not be more than 16 of them */ +#define NGRPS 16 + +/* + * Unix style credentials. + */ +struct authunix_parms { +	u_long	 aup_time; +	char	*aup_machname; +	int	 aup_uid; +	int	 aup_gid; +	u_int	 aup_len; +	int	*aup_gids; +}; + +extern bool_t xdr_authunix_parms(); + +/*  + * If a response verifier has flavor AUTH_SHORT,  + * then the body of the response verifier encapsulates the following structure; + * again it is serialized in the obvious fashion. + */ +struct short_hand_verf { +	struct opaque_auth new_cred; +}; diff --git a/lib/librpc/rpc/authunix_prot.c b/lib/librpc/rpc/authunix_prot.c new file mode 100644 index 000000000000..a60d99a57b73 --- /dev/null +++ b/lib/librpc/rpc/authunix_prot.c @@ -0,0 +1,66 @@ +/* @(#)authunix_prot.c	2.1 88/07/29 4.0 RPCSRC */ +/* + * Sun RPC is a product of Sun Microsystems, Inc. and is provided for + * unrestricted use provided that this legend is included on all tape + * media and as a part of the software program in whole or part.  Users + * may copy or modify Sun RPC without charge, but are not authorized + * to license or distribute it to anyone else except as part of a product or + * program developed by the user. + *  + * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE + * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR + * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. + *  + * Sun RPC is provided with no support and without any obligation on the + * part of Sun Microsystems, Inc. to assist in its use, correction, + * modification or enhancement. + *  + * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE + * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC + * OR ANY PART THEREOF. + *  + * In no event will Sun Microsystems, Inc. be liable for any lost revenue + * or profits or other special, indirect and consequential damages, even if + * Sun has been advised of the possibility of such damages. + *  + * Sun Microsystems, Inc. + * 2550 Garcia Avenue + * Mountain View, California  94043 + */ +#if !defined(lint) && defined(SCCSIDS) +static char sccsid[] = "@(#)authunix_prot.c 1.15 87/08/11 Copyr 1984 Sun Micro"; +#endif + +/* + * authunix_prot.c + * XDR for UNIX style authentication parameters for RPC + * + * Copyright (C) 1984, Sun Microsystems, Inc. + */ + + +#include <rpc/types.h> +#include <rpc/xdr.h> +#include <rpc/auth.h> +#include <rpc/auth_unix.h> + +/* + * XDR for unix authentication parameters. + */ +bool_t +xdr_authunix_parms(xdrs, p) +	register XDR *xdrs; +	register struct authunix_parms *p; +{ + +	if (xdr_u_long(xdrs, &(p->aup_time)) +	    && xdr_string(xdrs, &(p->aup_machname), MAX_MACHINE_NAME) +	    && xdr_int(xdrs, &(p->aup_uid)) +	    && xdr_int(xdrs, &(p->aup_gid)) +	    && xdr_array(xdrs, (caddr_t *)&(p->aup_gids), +		    &(p->aup_len), NGRPS, sizeof(int), xdr_int) ) { +		return (TRUE); +	} +	return (FALSE); +} + diff --git a/lib/librpc/rpc/bindresvport.c b/lib/librpc/rpc/bindresvport.c new file mode 100644 index 000000000000..63a68d36e15f --- /dev/null +++ b/lib/librpc/rpc/bindresvport.c @@ -0,0 +1,79 @@ +static  char sccsid[] = "@(#)bindresvport.c	2.2 88/07/29 4.0 RPCSRC 1.8 88/02/08 SMI"; +/* + * Sun RPC is a product of Sun Microsystems, Inc. and is provided for + * unrestricted use provided that this legend is included on all tape + * media and as a part of the software program in whole or part.  Users + * may copy or modify Sun RPC without charge, but are not authorized + * to license or distribute it to anyone else except as part of a product or + * program developed by the user. + *  + * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE + * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR + * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. + *  + * Sun RPC is provided with no support and without any obligation on the + * part of Sun Microsystems, Inc. to assist in its use, correction, + * modification or enhancement. + *  + * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE + * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC + * OR ANY PART THEREOF. + *  + * In no event will Sun Microsystems, Inc. be liable for any lost revenue + * or profits or other special, indirect and consequential damages, even if + * Sun has been advised of the possibility of such damages. + *  + * Sun Microsystems, Inc. + * 2550 Garcia Avenue + * Mountain View, California  94043 + */ + +/* + * Copyright (c) 1987 by Sun Microsystems, Inc. + */ + +#include <sys/types.h> +#include <sys/errno.h> +#include <sys/socket.h> +#include <netinet/in.h> + +/* + * Bind a socket to a privileged IP port + */ +bindresvport(sd, sin) +	int sd; +	struct sockaddr_in *sin; +{ +	int res; +	static short port; +	struct sockaddr_in myaddr; +	extern int errno; +	int i; + +#define STARTPORT 600 +#define ENDPORT (IPPORT_RESERVED - 1) +#define NPORTS	(ENDPORT - STARTPORT + 1) + +	if (sin == (struct sockaddr_in *)0) { +		sin = &myaddr; +		bzero(sin, sizeof (*sin)); +		sin->sin_family = AF_INET; +	} else if (sin->sin_family != AF_INET) { +		errno = EPFNOSUPPORT; +		return (-1); +	} +	if (port == 0) { +		port = (getpid() % NPORTS) + STARTPORT; +	} +	res = -1; +	errno = EADDRINUSE; +	for (i = 0; i < NPORTS && res < 0 && errno == EADDRINUSE; i++) { +		sin->sin_port = htons(port++); +		if (port > ENDPORT) { +			port = STARTPORT; +		} +		res = bind(sd, +		    (struct sockaddr *)sin, sizeof(struct sockaddr_in)); +	} +	return (res); +} diff --git a/lib/librpc/rpc/clnt.h b/lib/librpc/rpc/clnt.h new file mode 100644 index 000000000000..8c002a19faee --- /dev/null +++ b/lib/librpc/rpc/clnt.h @@ -0,0 +1,331 @@ +/* @(#)clnt.h	2.1 88/07/29 4.0 RPCSRC; from 1.31 88/02/08 SMI*/ +/* + * Sun RPC is a product of Sun Microsystems, Inc. and is provided for + * unrestricted use provided that this legend is included on all tape + * media and as a part of the software program in whole or part.  Users + * may copy or modify Sun RPC without charge, but are not authorized + * to license or distribute it to anyone else except as part of a product or + * program developed by the user. + *  + * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE + * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR + * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. + *  + * Sun RPC is provided with no support and without any obligation on the + * part of Sun Microsystems, Inc. to assist in its use, correction, + * modification or enhancement. + *  + * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE + * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC + * OR ANY PART THEREOF. + *  + * In no event will Sun Microsystems, Inc. be liable for any lost revenue + * or profits or other special, indirect and consequential damages, even if + * Sun has been advised of the possibility of such damages. + *  + * Sun Microsystems, Inc. + * 2550 Garcia Avenue + * Mountain View, California  94043 + */ + +/* + * clnt.h - Client side remote procedure call interface. + * + * Copyright (C) 1984, Sun Microsystems, Inc. + */ + +#ifndef _CLNT_ +#define _CLNT_ + +/* + * Rpc calls return an enum clnt_stat.  This should be looked at more, + * since each implementation is required to live with this (implementation + * independent) list of errors. + */ +enum clnt_stat { +	RPC_SUCCESS=0,			/* call succeeded */ +	/* +	 * local errors +	 */ +	RPC_CANTENCODEARGS=1,		/* can't encode arguments */ +	RPC_CANTDECODERES=2,		/* can't decode results */ +	RPC_CANTSEND=3,			/* failure in sending call */ +	RPC_CANTRECV=4,			/* failure in receiving result */ +	RPC_TIMEDOUT=5,			/* call timed out */ +	/* +	 * remote errors +	 */ +	RPC_VERSMISMATCH=6,		/* rpc versions not compatible */ +	RPC_AUTHERROR=7,		/* authentication error */ +	RPC_PROGUNAVAIL=8,		/* program not available */ +	RPC_PROGVERSMISMATCH=9,		/* program version mismatched */ +	RPC_PROCUNAVAIL=10,		/* procedure unavailable */ +	RPC_CANTDECODEARGS=11,		/* decode arguments error */ +	RPC_SYSTEMERROR=12,		/* generic "other problem" */ + +	/* +	 * callrpc & clnt_create errors +	 */ +	RPC_UNKNOWNHOST=13,		/* unknown host name */ +	RPC_UNKNOWNPROTO=17,		/* unkown protocol */ + +	/* +	 * _ create errors +	 */ +	RPC_PMAPFAILURE=14,		/* the pmapper failed in its call */ +	RPC_PROGNOTREGISTERED=15,	/* remote program is not registered */ +	/* +	 * unspecified error +	 */ +	RPC_FAILED=16 +}; + + +/* + * Error info. + */ +struct rpc_err { +	enum clnt_stat re_status; +	union { +		int RE_errno;		/* realated system error */ +		enum auth_stat RE_why;	/* why the auth error occurred */ +		struct { +			u_long low;	/* lowest verion supported */ +			u_long high;	/* highest verion supported */ +		} RE_vers; +		struct {		/* maybe meaningful if RPC_FAILED */ +			long s1; +			long s2; +		} RE_lb;		/* life boot & debugging only */ +	} ru; +#define	re_errno	ru.RE_errno +#define	re_why		ru.RE_why +#define	re_vers		ru.RE_vers +#define	re_lb		ru.RE_lb +}; + + +/* + * Client rpc handle. + * Created by individual implementations, see e.g. rpc_udp.c. + * Client is responsible for initializing auth, see e.g. auth_none.c. + */ +typedef struct { +	AUTH	*cl_auth;			/* authenticator */ +	struct clnt_ops { +		enum clnt_stat	(*cl_call)();	/* call remote procedure */ +		void		(*cl_abort)();	/* abort a call */ +		void		(*cl_geterr)();	/* get specific error code */ +		bool_t		(*cl_freeres)(); /* frees results */ +		void		(*cl_destroy)();/* destroy this structure */ +		bool_t          (*cl_control)();/* the ioctl() of rpc */ +	} *cl_ops; +	caddr_t			cl_private;	/* private stuff */ +} CLIENT; + + +/* + * client side rpc interface ops + * + * Parameter types are: + * + */ + +/* + * enum clnt_stat + * CLNT_CALL(rh, proc, xargs, argsp, xres, resp, timeout) + * 	CLIENT *rh; + *	u_long proc; + *	xdrproc_t xargs; + *	caddr_t argsp; + *	xdrproc_t xres; + *	caddr_t resp; + *	struct timeval timeout; + */ +#define	CLNT_CALL(rh, proc, xargs, argsp, xres, resp, secs)	\ +	((*(rh)->cl_ops->cl_call)(rh, proc, xargs, argsp, xres, resp, secs)) +#define	clnt_call(rh, proc, xargs, argsp, xres, resp, secs)	\ +	((*(rh)->cl_ops->cl_call)(rh, proc, xargs, argsp, xres, resp, secs)) + +/* + * void + * CLNT_ABORT(rh); + * 	CLIENT *rh; + */ +#define	CLNT_ABORT(rh)	((*(rh)->cl_ops->cl_abort)(rh)) +#define	clnt_abort(rh)	((*(rh)->cl_ops->cl_abort)(rh)) + +/* + * struct rpc_err + * CLNT_GETERR(rh); + * 	CLIENT *rh; + */ +#define	CLNT_GETERR(rh,errp)	((*(rh)->cl_ops->cl_geterr)(rh, errp)) +#define	clnt_geterr(rh,errp)	((*(rh)->cl_ops->cl_geterr)(rh, errp)) + + +/* + * bool_t + * CLNT_FREERES(rh, xres, resp); + * 	CLIENT *rh; + *	xdrproc_t xres; + *	caddr_t resp; + */ +#define	CLNT_FREERES(rh,xres,resp) ((*(rh)->cl_ops->cl_freeres)(rh,xres,resp)) +#define	clnt_freeres(rh,xres,resp) ((*(rh)->cl_ops->cl_freeres)(rh,xres,resp)) + +/* + * bool_t + * CLNT_CONTROL(cl, request, info) + *      CLIENT *cl; + *      u_int request; + *      char *info; + */ +#define	CLNT_CONTROL(cl,rq,in) ((*(cl)->cl_ops->cl_control)(cl,rq,in)) +#define	clnt_control(cl,rq,in) ((*(cl)->cl_ops->cl_control)(cl,rq,in)) + +/* + * control operations that apply to both udp and tcp transports + */ +#define CLSET_TIMEOUT       1   /* set timeout (timeval) */ +#define CLGET_TIMEOUT       2   /* get timeout (timeval) */ +#define CLGET_SERVER_ADDR   3   /* get server's address (sockaddr) */ +/* + * udp only control operations + */ +#define CLSET_RETRY_TIMEOUT 4   /* set retry timeout (timeval) */ +#define CLGET_RETRY_TIMEOUT 5   /* get retry timeout (timeval) */ + +/* + * void + * CLNT_DESTROY(rh); + * 	CLIENT *rh; + */ +#define	CLNT_DESTROY(rh)	((*(rh)->cl_ops->cl_destroy)(rh)) +#define	clnt_destroy(rh)	((*(rh)->cl_ops->cl_destroy)(rh)) + + +/* + * RPCTEST is a test program which is accessable on every rpc + * transport/port.  It is used for testing, performance evaluation, + * and network administration. + */ + +#define RPCTEST_PROGRAM		((u_long)1) +#define RPCTEST_VERSION		((u_long)1) +#define RPCTEST_NULL_PROC	((u_long)2) +#define RPCTEST_NULL_BATCH_PROC	((u_long)3) + +/* + * By convention, procedure 0 takes null arguments and returns them + */ + +#define NULLPROC ((u_long)0) + +/* + * Below are the client handle creation routines for the various + * implementations of client side rpc.  They can return NULL if a  + * creation failure occurs. + */ + +/* + * Memory based rpc (for speed check and testing) + * CLIENT * + * clntraw_create(prog, vers) + *	u_long prog; + *	u_long vers; + */ +extern CLIENT *clntraw_create(); + + +/* + * Generic client creation routine. Supported protocols are "udp" and "tcp" + */ +extern CLIENT * +clnt_create(/*host, prog, vers, prot*/); /* +	char *host; 	-- hostname +	u_long prog;	-- program number +	u_long vers;	-- version number +	char *prot;	-- protocol +*/ + + + + +/* + * TCP based rpc + * CLIENT * + * clnttcp_create(raddr, prog, vers, sockp, sendsz, recvsz) + *	struct sockaddr_in *raddr; + *	u_long prog; + *	u_long version; + *	register int *sockp; + *	u_int sendsz; + *	u_int recvsz; + */ +extern CLIENT *clnttcp_create(); + +/* + * UDP based rpc. + * CLIENT * + * clntudp_create(raddr, program, version, wait, sockp) + *	struct sockaddr_in *raddr; + *	u_long program; + *	u_long version; + *	struct timeval wait; + *	int *sockp; + * + * Same as above, but you specify max packet sizes. + * CLIENT * + * clntudp_bufcreate(raddr, program, version, wait, sockp, sendsz, recvsz) + *	struct sockaddr_in *raddr; + *	u_long program; + *	u_long version; + *	struct timeval wait; + *	int *sockp; + *	u_int sendsz; + *	u_int recvsz; + */ +extern CLIENT *clntudp_create(); +extern CLIENT *clntudp_bufcreate(); + +/* + * Print why creation failed + */ +void clnt_pcreateerror(/* char *msg */);	/* stderr */ +char *clnt_spcreateerror(/* char *msg */);	/* string */ + +/* + * Like clnt_perror(), but is more verbose in its output + */  +void clnt_perrno(/* enum clnt_stat num */);	/* stderr */ + +/* + * Print an English error message, given the client error code + */ +void clnt_perror(/* CLIENT *clnt, char *msg */); 	/* stderr */ +char *clnt_sperror(/* CLIENT *clnt, char *msg */);	/* string */ + +/*  + * If a creation fails, the following allows the user to figure out why. + */ +struct rpc_createerr { +	enum clnt_stat cf_stat; +	struct rpc_err cf_error; /* useful when cf_stat == RPC_PMAPFAILURE */ +}; + +extern struct rpc_createerr rpc_createerr; + + + +/* + * Copy error message to buffer. + */ +char *clnt_sperrno(/* enum clnt_stat num */);	/* string */ + + + +#define UDPMSGSIZE	8800	/* rpc imposed limit on udp msg size */ +#define RPCSMALLMSGSIZE	400	/* a more reasonable packet size */ + +#endif /*!_CLNT_*/ diff --git a/lib/librpc/rpc/clnt_generic.c b/lib/librpc/rpc/clnt_generic.c new file mode 100644 index 000000000000..e54e77828b2a --- /dev/null +++ b/lib/librpc/rpc/clnt_generic.c @@ -0,0 +1,110 @@ +/* @(#)clnt_generic.c	2.2 88/08/01 4.0 RPCSRC */ +/* + * Sun RPC is a product of Sun Microsystems, Inc. and is provided for + * unrestricted use provided that this legend is included on all tape + * media and as a part of the software program in whole or part.  Users + * may copy or modify Sun RPC without charge, but are not authorized + * to license or distribute it to anyone else except as part of a product or + * program developed by the user. + *  + * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE + * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR + * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. + *  + * Sun RPC is provided with no support and without any obligation on the + * part of Sun Microsystems, Inc. to assist in its use, correction, + * modification or enhancement. + * + * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE + * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC + * OR ANY PART THEREOF. + *  + * In no event will Sun Microsystems, Inc. be liable for any lost revenue + * or profits or other special, indirect and consequential damages, even if + * Sun has been advised of the possibility of such damages. + *  + * Sun Microsystems, Inc. + * 2550 Garcia Avenue + * Mountain View, California  94043 + */ +#if !defined(lint) && defined(SCCSIDS) +static char sccsid[] = "@(#)clnt_generic.c 1.4 87/08/11 (C) 1987 SMI"; +#endif +/* + * Copyright (C) 1987, Sun Microsystems, Inc. + */ +#include <rpc/rpc.h> +#include <sys/socket.h> +#include <sys/errno.h> +#include <netdb.h> + +/* + * Generic client creation: takes (hostname, program-number, protocol) and + * returns client handle. Default options are set, which the user can  + * change using the rpc equivalent of ioctl()'s. + */ +CLIENT * +clnt_create(hostname, prog, vers, proto) +	char *hostname; +	unsigned prog; +	unsigned vers; +	char *proto; +{ +	struct hostent *h; +	struct protoent *p; +	struct sockaddr_in sin; +	int sock; +	struct timeval tv; +	CLIENT *client; + +	h = gethostbyname(hostname); +	if (h == NULL) { +		rpc_createerr.cf_stat = RPC_UNKNOWNHOST; +		return (NULL); +	} +	if (h->h_addrtype != AF_INET) { +		/* +		 * Only support INET for now +		 */ +		rpc_createerr.cf_stat = RPC_SYSTEMERROR; +		rpc_createerr.cf_error.re_errno = EAFNOSUPPORT;  +		return (NULL); +	} +	sin.sin_family = h->h_addrtype; +	sin.sin_port = 0; +	bzero(sin.sin_zero, sizeof(sin.sin_zero)); +	bcopy(h->h_addr, (char*)&sin.sin_addr, h->h_length); +	p = getprotobyname(proto); +	if (p == NULL) { +		rpc_createerr.cf_stat = RPC_UNKNOWNPROTO; +		rpc_createerr.cf_error.re_errno = EPFNOSUPPORT;  +		return (NULL); +	} +	sock = RPC_ANYSOCK; +	switch (p->p_proto) { +	case IPPROTO_UDP: +		tv.tv_sec = 5; +		tv.tv_usec = 0; +		client = clntudp_create(&sin, prog, vers, tv, &sock); +		if (client == NULL) { +			return (NULL); +		} +		tv.tv_sec = 25; +		clnt_control(client, CLSET_TIMEOUT, &tv); +		break; +	case IPPROTO_TCP: +		client = clnttcp_create(&sin, prog, vers, &sock, 0, 0); +		if (client == NULL) { +			return (NULL); +		} +		tv.tv_sec = 25; +		tv.tv_usec = 0; +		clnt_control(client, CLSET_TIMEOUT, &tv); +		break; +	default: +		rpc_createerr.cf_stat = RPC_SYSTEMERROR; +		rpc_createerr.cf_error.re_errno = EPFNOSUPPORT;  +		return (NULL); +	} +	return (client); +} diff --git a/lib/librpc/rpc/clnt_perror.c b/lib/librpc/rpc/clnt_perror.c new file mode 100644 index 000000000000..c618c5f3e97f --- /dev/null +++ b/lib/librpc/rpc/clnt_perror.c @@ -0,0 +1,302 @@ +/* @(#)clnt_perror.c	2.1 88/07/29 4.0 RPCSRC */ +/* + * Sun RPC is a product of Sun Microsystems, Inc. and is provided for + * unrestricted use provided that this legend is included on all tape + * media and as a part of the software program in whole or part.  Users + * may copy or modify Sun RPC without charge, but are not authorized + * to license or distribute it to anyone else except as part of a product or + * program developed by the user. + *  + * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE + * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR + * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. + *  + * Sun RPC is provided with no support and without any obligation on the + * part of Sun Microsystems, Inc. to assist in its use, correction, + * modification or enhancement. + *  + * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE + * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC + * OR ANY PART THEREOF. + *  + * In no event will Sun Microsystems, Inc. be liable for any lost revenue + * or profits or other special, indirect and consequential damages, even if + * Sun has been advised of the possibility of such damages. + *  + * Sun Microsystems, Inc. + * 2550 Garcia Avenue + * Mountain View, California  94043 + */ +#if !defined(lint) && defined(SCCSIDS) +static char sccsid[] = "@(#)clnt_perror.c 1.15 87/10/07 Copyr 1984 Sun Micro"; +#endif + +/* + * clnt_perror.c + * + * Copyright (C) 1984, Sun Microsystems, Inc. + * + */ +#include <stdio.h> + +#include <rpc/types.h> +#include <rpc/auth.h> +#include <rpc/clnt.h> + +static char *auth_errmsg(); + +extern char *strcpy(); + +static char *buf; + +static char * +_buf() +{ + +	if (buf == 0) +		buf = (char *)malloc(256); +	return (buf); +} + +/* + * Print reply error info + */ +char * +clnt_sperror(rpch, s) +	CLIENT *rpch; +	char *s; +{ +	struct rpc_err e; +	void clnt_perrno(); +	char *err; +	char *str = _buf(); +	char *strstart = str; + +	if (str == 0) +		return (0); +	CLNT_GETERR(rpch, &e); + +	(void) sprintf(str, "%s: ", s);   +	str += strlen(str); + +	(void) strcpy(str, clnt_sperrno(e.re_status));   +	str += strlen(str); + +	switch (e.re_status) { +	case RPC_SUCCESS: +	case RPC_CANTENCODEARGS: +	case RPC_CANTDECODERES: +	case RPC_TIMEDOUT:      +	case RPC_PROGUNAVAIL: +	case RPC_PROCUNAVAIL: +	case RPC_CANTDECODEARGS: +	case RPC_SYSTEMERROR: +	case RPC_UNKNOWNHOST: +	case RPC_UNKNOWNPROTO: +	case RPC_PMAPFAILURE: +	case RPC_PROGNOTREGISTERED: +	case RPC_FAILED: +		break; + +	case RPC_CANTSEND: +	case RPC_CANTRECV: +		(void) sprintf(str, "; errno = %s", +		    strerror(e.re_errno));  +		str += strlen(str); +		break; + +	case RPC_VERSMISMATCH: +		(void) sprintf(str, +			"; low version = %lu, high version = %lu",  +			e.re_vers.low, e.re_vers.high); +		str += strlen(str); +		break; + +	case RPC_AUTHERROR: +		err = auth_errmsg(e.re_why); +		(void) sprintf(str,"; why = "); +		str += strlen(str); +		if (err != NULL) { +			(void) sprintf(str, "%s",err); +		} else { +			(void) sprintf(str, +				"(unknown authentication error - %d)", +				(int) e.re_why); +		} +		str += strlen(str); +		break; + +	case RPC_PROGVERSMISMATCH: +		(void) sprintf(str,  +			"; low version = %lu, high version = %lu",  +			e.re_vers.low, e.re_vers.high); +		str += strlen(str); +		break; + +	default:	/* unknown */ +		(void) sprintf(str,  +			"; s1 = %lu, s2 = %lu",  +			e.re_lb.s1, e.re_lb.s2); +		str += strlen(str); +		break; +	} +	(void) sprintf(str, "\n"); +	return(strstart) ; +} + +void +clnt_perror(rpch, s) +	CLIENT *rpch; +	char *s; +{ +	(void) fprintf(stderr,"%s",clnt_sperror(rpch,s)); +} + + +struct rpc_errtab { +	enum clnt_stat status; +	char *message; +}; + +static struct rpc_errtab  rpc_errlist[] = { +	{ RPC_SUCCESS,  +		"RPC: Success" },  +	{ RPC_CANTENCODEARGS,  +		"RPC: Can't encode arguments" }, +	{ RPC_CANTDECODERES,  +		"RPC: Can't decode result" }, +	{ RPC_CANTSEND,  +		"RPC: Unable to send" }, +	{ RPC_CANTRECV,  +		"RPC: Unable to receive" }, +	{ RPC_TIMEDOUT,  +		"RPC: Timed out" }, +	{ RPC_VERSMISMATCH,  +		"RPC: Incompatible versions of RPC" }, +	{ RPC_AUTHERROR,  +		"RPC: Authentication error" }, +	{ RPC_PROGUNAVAIL,  +		"RPC: Program unavailable" }, +	{ RPC_PROGVERSMISMATCH,  +		"RPC: Program/version mismatch" }, +	{ RPC_PROCUNAVAIL,  +		"RPC: Procedure unavailable" }, +	{ RPC_CANTDECODEARGS,  +		"RPC: Server can't decode arguments" }, +	{ RPC_SYSTEMERROR,  +		"RPC: Remote system error" }, +	{ RPC_UNKNOWNHOST,  +		"RPC: Unknown host" }, +	{ RPC_UNKNOWNPROTO, +		"RPC: Unknown protocol" }, +	{ RPC_PMAPFAILURE,  +		"RPC: Port mapper failure" }, +	{ RPC_PROGNOTREGISTERED,  +		"RPC: Program not registered"}, +	{ RPC_FAILED,  +		"RPC: Failed (unspecified error)"} +}; + + +/* + * This interface for use by clntrpc + */ +char * +clnt_sperrno(stat) +	enum clnt_stat stat; +{ +	int i; + +	for (i = 0; i < sizeof(rpc_errlist)/sizeof(struct rpc_errtab); i++) { +		if (rpc_errlist[i].status == stat) { +			return (rpc_errlist[i].message); +		} +	} +	return ("RPC: (unknown error code)"); +} + +void +clnt_perrno(num) +	enum clnt_stat num; +{ +	(void) fprintf(stderr,"%s",clnt_sperrno(num)); +} + + +char * +clnt_spcreateerror(s) +	char *s; +{ +	extern int sys_nerr; +	char *str = _buf(); + +	if (str == 0) +		return(0); +	(void) sprintf(str, "%s: ", s); +	(void) strcat(str, clnt_sperrno(rpc_createerr.cf_stat)); +	switch (rpc_createerr.cf_stat) { +	case RPC_PMAPFAILURE: +		(void) strcat(str, " - "); +		(void) strcat(str, +		    clnt_sperrno(rpc_createerr.cf_error.re_status)); +		break; + +	case RPC_SYSTEMERROR: +		(void) strcat(str, " - "); +		if (rpc_createerr.cf_error.re_errno > 0 +		    && rpc_createerr.cf_error.re_errno < sys_nerr) +			(void) strcat(str, +			    strerror(rpc_createerr.cf_error.re_errno)); +		else +			(void) sprintf(&str[strlen(str)], "Error %d", +			    rpc_createerr.cf_error.re_errno); +		break; +	} +	(void) strcat(str, "\n"); +	return (str); +} + +void +clnt_pcreateerror(s) +	char *s; +{ +	(void) fprintf(stderr,"%s",clnt_spcreateerror(s)); +} + +struct auth_errtab { +	enum auth_stat status;	 +	char *message; +}; + +static struct auth_errtab auth_errlist[] = { +	{ AUTH_OK, +		"Authentication OK" }, +	{ AUTH_BADCRED, +		"Invalid client credential" }, +	{ AUTH_REJECTEDCRED, +		"Server rejected credential" }, +	{ AUTH_BADVERF, +		"Invalid client verifier" }, +	{ AUTH_REJECTEDVERF, +		"Server rejected verifier" }, +	{ AUTH_TOOWEAK, +		"Client credential too weak" }, +	{ AUTH_INVALIDRESP, +		"Invalid server verifier" }, +	{ AUTH_FAILED, +		"Failed (unspecified error)" }, +}; + +static char * +auth_errmsg(stat) +	enum auth_stat stat; +{ +	int i; + +	for (i = 0; i < sizeof(auth_errlist)/sizeof(struct auth_errtab); i++) { +		if (auth_errlist[i].status == stat) { +			return(auth_errlist[i].message); +		} +	} +	return(NULL); +} diff --git a/lib/librpc/rpc/clnt_raw.c b/lib/librpc/rpc/clnt_raw.c new file mode 100644 index 000000000000..89059ae2da77 --- /dev/null +++ b/lib/librpc/rpc/clnt_raw.c @@ -0,0 +1,238 @@ +/* @(#)clnt_raw.c	2.2 88/08/01 4.0 RPCSRC */ +/* + * Sun RPC is a product of Sun Microsystems, Inc. and is provided for + * unrestricted use provided that this legend is included on all tape + * media and as a part of the software program in whole or part.  Users + * may copy or modify Sun RPC without charge, but are not authorized + * to license or distribute it to anyone else except as part of a product or + * program developed by the user. + *  + * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE + * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR + * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. + *  + * Sun RPC is provided with no support and without any obligation on the + * part of Sun Microsystems, Inc. to assist in its use, correction, + * modification or enhancement. + * + * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE + * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC + * OR ANY PART THEREOF. + *  + * In no event will Sun Microsystems, Inc. be liable for any lost revenue + * or profits or other special, indirect and consequential damages, even if + * Sun has been advised of the possibility of such damages. + *  + * Sun Microsystems, Inc. + * 2550 Garcia Avenue + * Mountain View, California  94043 + */ +#if !defined(lint) && defined(SCCSIDS) +static char sccsid[] = "@(#)clnt_raw.c 1.22 87/08/11 Copyr 1984 Sun Micro"; +#endif + +/* + * clnt_raw.c + * + * Copyright (C) 1984, Sun Microsystems, Inc. + * + * Memory based rpc for simple testing and timing. + * Interface to create an rpc client and server in the same process. + * This lets us similate rpc and get round trip overhead, without + * any interference from the kernal. + */ + +#include <rpc/rpc.h> + +#define MCALL_MSG_SIZE 24 + +/* + * This is the "network" we will be moving stuff over. + */ +static struct clntraw_private { +	CLIENT	client_object; +	XDR	xdr_stream; +	char	_raw_buf[UDPMSGSIZE]; +	char	mashl_callmsg[MCALL_MSG_SIZE]; +	u_int	mcnt; +} *clntraw_private; + +static enum clnt_stat	clntraw_call(); +static void		clntraw_abort(); +static void		clntraw_geterr(); +static bool_t		clntraw_freeres(); +static bool_t		clntraw_control(); +static void		clntraw_destroy(); + +static struct clnt_ops client_ops = { +	clntraw_call, +	clntraw_abort, +	clntraw_geterr, +	clntraw_freeres, +	clntraw_destroy, +	clntraw_control +}; + +void	svc_getreq(); + +/* + * Create a client handle for memory based rpc. + */ +CLIENT * +clntraw_create(prog, vers) +	u_long prog; +	u_long vers; +{ +	register struct clntraw_private *clp = clntraw_private; +	struct rpc_msg call_msg; +	XDR *xdrs = &clp->xdr_stream; +	CLIENT	*client = &clp->client_object; + +	if (clp == 0) { +		clp = (struct clntraw_private *)calloc(1, sizeof (*clp)); +		if (clp == 0) +			return (0); +		clntraw_private = clp; +	} +	/* +	 * pre-serialize the staic part of the call msg and stash it away +	 */ +	call_msg.rm_direction = CALL; +	call_msg.rm_call.cb_rpcvers = RPC_MSG_VERSION; +	call_msg.rm_call.cb_prog = prog; +	call_msg.rm_call.cb_vers = vers; +	xdrmem_create(xdrs, clp->mashl_callmsg, MCALL_MSG_SIZE, XDR_ENCODE);  +	if (! xdr_callhdr(xdrs, &call_msg)) { +		perror("clnt_raw.c - Fatal header serialization error."); +	} +	clp->mcnt = XDR_GETPOS(xdrs); +	XDR_DESTROY(xdrs); + +	/* +	 * Set xdrmem for client/server shared buffer +	 */ +	xdrmem_create(xdrs, clp->_raw_buf, UDPMSGSIZE, XDR_FREE); + +	/* +	 * create client handle +	 */ +	client->cl_ops = &client_ops; +	client->cl_auth = authnone_create(); +	return (client); +} + +static enum clnt_stat  +clntraw_call(h, proc, xargs, argsp, xresults, resultsp, timeout) +	CLIENT *h; +	u_long proc; +	xdrproc_t xargs; +	caddr_t argsp; +	xdrproc_t xresults; +	caddr_t resultsp; +	struct timeval timeout; +{ +	register struct clntraw_private *clp = clntraw_private; +	register XDR *xdrs = &clp->xdr_stream; +	struct rpc_msg msg; +	enum clnt_stat status; +	struct rpc_err error; + +	if (clp == 0) +		return (RPC_FAILED); +call_again: +	/* +	 * send request +	 */ +	xdrs->x_op = XDR_ENCODE; +	XDR_SETPOS(xdrs, 0); +	((struct rpc_msg *)clp->mashl_callmsg)->rm_xid ++ ; +	if ((! XDR_PUTBYTES(xdrs, clp->mashl_callmsg, clp->mcnt)) || +	    (! XDR_PUTLONG(xdrs, (long *)&proc)) || +	    (! AUTH_MARSHALL(h->cl_auth, xdrs)) || +	    (! (*xargs)(xdrs, argsp))) { +		return (RPC_CANTENCODEARGS); +	} +	(void)XDR_GETPOS(xdrs);  /* called just to cause overhead */ + +	/* +	 * We have to call server input routine here because this is +	 * all going on in one process. Yuk. +	 */ +	svc_getreq(1); + +	/* +	 * get results +	 */ +	xdrs->x_op = XDR_DECODE; +	XDR_SETPOS(xdrs, 0); +	msg.acpted_rply.ar_verf = _null_auth; +	msg.acpted_rply.ar_results.where = resultsp; +	msg.acpted_rply.ar_results.proc = xresults; +	if (! xdr_replymsg(xdrs, &msg)) +		return (RPC_CANTDECODERES); +	_seterr_reply(&msg, &error); +	status = error.re_status; + +	if (status == RPC_SUCCESS) { +		if (! AUTH_VALIDATE(h->cl_auth, &msg.acpted_rply.ar_verf)) { +			status = RPC_AUTHERROR; +		} +	}  /* end successful completion */ +	else { +		if (AUTH_REFRESH(h->cl_auth)) +			goto call_again; +	}  /* end of unsuccessful completion */ + +	if (status == RPC_SUCCESS) { +		if (! AUTH_VALIDATE(h->cl_auth, &msg.acpted_rply.ar_verf)) { +			status = RPC_AUTHERROR; +		} +		if (msg.acpted_rply.ar_verf.oa_base != NULL) { +			xdrs->x_op = XDR_FREE; +			(void)xdr_opaque_auth(xdrs, &(msg.acpted_rply.ar_verf)); +		} +	} + +	return (status); +} + +static void +clntraw_geterr() +{ +} + + +static bool_t +clntraw_freeres(cl, xdr_res, res_ptr) +	CLIENT *cl; +	xdrproc_t xdr_res; +	caddr_t res_ptr; +{ +	register struct clntraw_private *clp = clntraw_private; +	register XDR *xdrs = &clp->xdr_stream; +	bool_t rval; + +	if (clp == 0) +	{ +		rval = (bool_t) RPC_FAILED; +		return (rval); +	} +	xdrs->x_op = XDR_FREE; +	return ((*xdr_res)(xdrs, res_ptr)); +} + +static void +clntraw_abort() +{ +} + +static bool_t +clntraw_control() +{ +	return (FALSE); +} + +static void +clntraw_destroy() +{ +} diff --git a/lib/librpc/rpc/clnt_simple.c b/lib/librpc/rpc/clnt_simple.c new file mode 100644 index 000000000000..043ce0a3ebda --- /dev/null +++ b/lib/librpc/rpc/clnt_simple.c @@ -0,0 +1,112 @@ +/* @(#)clnt_simple.c	2.2 88/08/01 4.0 RPCSRC */ +/* + * Sun RPC is a product of Sun Microsystems, Inc. and is provided for + * unrestricted use provided that this legend is included on all tape + * media and as a part of the software program in whole or part.  Users + * may copy or modify Sun RPC without charge, but are not authorized + * to license or distribute it to anyone else except as part of a product or + * program developed by the user. + *  + * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE + * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR + * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. + *  + * Sun RPC is provided with no support and without any obligation on the + * part of Sun Microsystems, Inc. to assist in its use, correction, + * modification or enhancement. + *  + * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE + * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC + * OR ANY PART THEREOF. + *  + * In no event will Sun Microsystems, Inc. be liable for any lost revenue + * or profits or other special, indirect and consequential damages, even if + * Sun has been advised of the possibility of such damages. + *  + * Sun Microsystems, Inc. + * 2550 Garcia Avenue + * Mountain View, California  94043 + */ +#if !defined(lint) && defined(SCCSIDS) +static char sccsid[] = "@(#)clnt_simple.c 1.35 87/08/11 Copyr 1984 Sun Micro"; +#endif + +/*  + * clnt_simple.c + * Simplified front end to rpc. + * + * Copyright (C) 1984, Sun Microsystems, Inc. + */ + +#include <stdio.h> +#include <rpc/rpc.h> +#include <sys/socket.h> +#include <netdb.h> +#include <strings.h> + +static struct callrpc_private { +	CLIENT	*client; +	int	socket; +	int	oldprognum, oldversnum, valid; +	char	*oldhost; +} *callrpc_private; + +callrpc(host, prognum, versnum, procnum, inproc, in, outproc, out) +	char *host; +	xdrproc_t inproc, outproc; +	char *in, *out; +{ +	register struct callrpc_private *crp = callrpc_private; +	struct sockaddr_in server_addr; +	enum clnt_stat clnt_stat; +	struct hostent *hp; +	struct timeval timeout, tottimeout; + +	if (crp == 0) { +		crp = (struct callrpc_private *)calloc(1, sizeof (*crp)); +		if (crp == 0) +			return (0); +		callrpc_private = crp; +	} +	if (crp->oldhost == NULL) { +		crp->oldhost = malloc(256); +		crp->oldhost[0] = 0; +		crp->socket = RPC_ANYSOCK; +	} +	if (crp->valid && crp->oldprognum == prognum && crp->oldversnum == versnum +		&& strcmp(crp->oldhost, host) == 0) { +		/* reuse old client */		 +	} else { +		crp->valid = 0; +		(void)close(crp->socket); +		crp->socket = RPC_ANYSOCK; +		if (crp->client) { +			clnt_destroy(crp->client); +			crp->client = NULL; +		} +		if ((hp = gethostbyname(host)) == NULL) +			return ((int) RPC_UNKNOWNHOST); +		timeout.tv_usec = 0; +		timeout.tv_sec = 5; +		bcopy(hp->h_addr, (char *)&server_addr.sin_addr, hp->h_length); +		server_addr.sin_family = AF_INET; +		server_addr.sin_port =  0; +		if ((crp->client = clntudp_create(&server_addr, (u_long)prognum, +		    (u_long)versnum, timeout, &crp->socket)) == NULL) +			return ((int) rpc_createerr.cf_stat); +		crp->valid = 1; +		crp->oldprognum = prognum; +		crp->oldversnum = versnum; +		(void) strcpy(crp->oldhost, host); +	} +	tottimeout.tv_sec = 25; +	tottimeout.tv_usec = 0; +	clnt_stat = clnt_call(crp->client, procnum, inproc, in, +	    outproc, out, tottimeout); +	/*  +	 * if call failed, empty cache +	 */ +	if (clnt_stat != RPC_SUCCESS) +		crp->valid = 0; +	return ((int) clnt_stat); +} diff --git a/lib/librpc/rpc/clnt_tcp.c b/lib/librpc/rpc/clnt_tcp.c new file mode 100644 index 000000000000..2222bc6577be --- /dev/null +++ b/lib/librpc/rpc/clnt_tcp.c @@ -0,0 +1,466 @@ +/* @(#)clnt_tcp.c	2.2 88/08/01 4.0 RPCSRC */ +/* + * Sun RPC is a product of Sun Microsystems, Inc. and is provided for + * unrestricted use provided that this legend is included on all tape + * media and as a part of the software program in whole or part.  Users + * may copy or modify Sun RPC without charge, but are not authorized + * to license or distribute it to anyone else except as part of a product or + * program developed by the user. + *  + * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE + * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR + * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. + *  + * Sun RPC is provided with no support and without any obligation on the + * part of Sun Microsystems, Inc. to assist in its use, correction, + * modification or enhancement. + *  + * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE + * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC + * OR ANY PART THEREOF. + *  + * In no event will Sun Microsystems, Inc. be liable for any lost revenue + * or profits or other special, indirect and consequential damages, even if + * Sun has been advised of the possibility of such damages. + *  + * Sun Microsystems, Inc. + * 2550 Garcia Avenue + * Mountain View, California  94043 + */ +#if !defined(lint) && defined(SCCSIDS) +static char sccsid[] = "@(#)clnt_tcp.c 1.37 87/10/05 Copyr 1984 Sun Micro"; +#endif +  +/* + * clnt_tcp.c, Implements a TCP/IP based, client side RPC. + * + * Copyright (C) 1984, Sun Microsystems, Inc. + * + * TCP based RPC supports 'batched calls'. + * A sequence of calls may be batched-up in a send buffer.  The rpc call + * return immediately to the client even though the call was not necessarily + * sent.  The batching occurs if the results' xdr routine is NULL (0) AND + * the rpc timeout value is zero (see clnt.h, rpc). + * + * Clients should NOT casually batch calls that in fact return results; that is, + * the server side should be aware that a call is batched and not produce any + * return message.  Batched calls that produce many result messages can + * deadlock (netlock) the client and the server.... + * + * Now go hang yourself. + */ + +#include <stdio.h> +#include <rpc/rpc.h> +#include <sys/socket.h> +#include <netdb.h> +#include <errno.h> +#include <rpc/pmap_clnt.h> + +#define MCALL_MSG_SIZE 24 + +extern int errno; + +static int	readtcp(); +static int	writetcp(); + +static enum clnt_stat	clnttcp_call(); +static void		clnttcp_abort(); +static void		clnttcp_geterr(); +static bool_t		clnttcp_freeres(); +static bool_t           clnttcp_control(); +static void		clnttcp_destroy(); + +static struct clnt_ops tcp_ops = { +	clnttcp_call, +	clnttcp_abort, +	clnttcp_geterr, +	clnttcp_freeres, +	clnttcp_destroy, +	clnttcp_control +}; + +struct ct_data { +	int		ct_sock; +	bool_t		ct_closeit; +	struct timeval	ct_wait; +	bool_t          ct_waitset;       /* wait set by clnt_control? */ +	struct sockaddr_in ct_addr;  +	struct rpc_err	ct_error; +	char		ct_mcall[MCALL_MSG_SIZE];	/* marshalled callmsg */ +	u_int		ct_mpos;			/* pos after marshal */ +	XDR		ct_xdrs; +}; + +/* + * Create a client handle for a tcp/ip connection. + * If *sockp<0, *sockp is set to a newly created TCP socket and it is + * connected to raddr.  If *sockp non-negative then + * raddr is ignored.  The rpc/tcp package does buffering + * similar to stdio, so the client must pick send and receive buffer sizes,]; + * 0 => use the default. + * If raddr->sin_port is 0, then a binder on the remote machine is + * consulted for the right port number. + * NB: *sockp is copied into a private area. + * NB: It is the clients responsibility to close *sockp. + * NB: The rpch->cl_auth is set null authentication.  Caller may wish to set this + * something more useful. + */ +CLIENT * +clnttcp_create(raddr, prog, vers, sockp, sendsz, recvsz) +	struct sockaddr_in *raddr; +	u_long prog; +	u_long vers; +	register int *sockp; +	u_int sendsz; +	u_int recvsz; +{ +	CLIENT *h; +	register struct ct_data *ct; +	struct timeval now; +	struct rpc_msg call_msg; + +	h  = (CLIENT *)mem_alloc(sizeof(*h)); +	if (h == NULL) { +		(void)fprintf(stderr, "clnttcp_create: out of memory\n"); +		rpc_createerr.cf_stat = RPC_SYSTEMERROR; +		rpc_createerr.cf_error.re_errno = errno; +		goto fooy; +	} +	ct = (struct ct_data *)mem_alloc(sizeof(*ct)); +	if (ct == NULL) { +		(void)fprintf(stderr, "clnttcp_create: out of memory\n"); +		rpc_createerr.cf_stat = RPC_SYSTEMERROR; +		rpc_createerr.cf_error.re_errno = errno; +		goto fooy; +	} + +	/* +	 * If no port number given ask the pmap for one +	 */ +	if (raddr->sin_port == 0) { +		u_short port; +		if ((port = pmap_getport(raddr, prog, vers, IPPROTO_TCP)) == 0) { +			mem_free((caddr_t)ct, sizeof(struct ct_data)); +			mem_free((caddr_t)h, sizeof(CLIENT)); +			return ((CLIENT *)NULL); +		} +		raddr->sin_port = htons(port); +	} + +	/* +	 * If no socket given, open one +	 */ +	if (*sockp < 0) { +		*sockp = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); +		(void)bindresvport(*sockp, (struct sockaddr_in *)0); +		if ((*sockp < 0) +		    || (connect(*sockp, (struct sockaddr *)raddr, +		    sizeof(*raddr)) < 0)) { +			rpc_createerr.cf_stat = RPC_SYSTEMERROR; +			rpc_createerr.cf_error.re_errno = errno; +			(void)close(*sockp); +			goto fooy; +		} +		ct->ct_closeit = TRUE; +	} else { +		ct->ct_closeit = FALSE; +	} + +	/* +	 * Set up private data struct +	 */ +	ct->ct_sock = *sockp; +	ct->ct_wait.tv_usec = 0; +	ct->ct_waitset = FALSE; +	ct->ct_addr = *raddr; + +	/* +	 * Initialize call message +	 */ +	(void)gettimeofday(&now, (struct timezone *)0); +	call_msg.rm_xid = getpid() ^ now.tv_sec ^ now.tv_usec; +	call_msg.rm_direction = CALL; +	call_msg.rm_call.cb_rpcvers = RPC_MSG_VERSION; +	call_msg.rm_call.cb_prog = prog; +	call_msg.rm_call.cb_vers = vers; + +	/* +	 * pre-serialize the staic part of the call msg and stash it away +	 */ +	xdrmem_create(&(ct->ct_xdrs), ct->ct_mcall, MCALL_MSG_SIZE, +	    XDR_ENCODE); +	if (! xdr_callhdr(&(ct->ct_xdrs), &call_msg)) { +		if (ct->ct_closeit) { +			(void)close(*sockp); +		} +		goto fooy; +	} +	ct->ct_mpos = XDR_GETPOS(&(ct->ct_xdrs)); +	XDR_DESTROY(&(ct->ct_xdrs)); + +	/* +	 * Create a client handle which uses xdrrec for serialization +	 * and authnone for authentication. +	 */ +	xdrrec_create(&(ct->ct_xdrs), sendsz, recvsz, +	    (caddr_t)ct, readtcp, writetcp); +	h->cl_ops = &tcp_ops; +	h->cl_private = (caddr_t) ct; +	h->cl_auth = authnone_create(); +	return (h); + +fooy: +	/* +	 * Something goofed, free stuff and barf +	 */ +	mem_free((caddr_t)ct, sizeof(struct ct_data)); +	mem_free((caddr_t)h, sizeof(CLIENT)); +	return ((CLIENT *)NULL); +} + +static enum clnt_stat +clnttcp_call(h, proc, xdr_args, args_ptr, xdr_results, results_ptr, timeout) +	register CLIENT *h; +	u_long proc; +	xdrproc_t xdr_args; +	caddr_t args_ptr; +	xdrproc_t xdr_results; +	caddr_t results_ptr; +	struct timeval timeout; +{ +	register struct ct_data *ct = (struct ct_data *) h->cl_private; +	register XDR *xdrs = &(ct->ct_xdrs); +	struct rpc_msg reply_msg; +	u_long x_id; +	u_long *msg_x_id = (u_long *)(ct->ct_mcall);	/* yuk */ +	register bool_t shipnow; +	int refreshes = 2; + +	if (!ct->ct_waitset) { +		ct->ct_wait = timeout; +	} + +	shipnow = +	    (xdr_results == (xdrproc_t)0 && timeout.tv_sec == 0 +	    && timeout.tv_usec == 0) ? FALSE : TRUE; + +call_again: +	xdrs->x_op = XDR_ENCODE; +	ct->ct_error.re_status = RPC_SUCCESS; +	x_id = ntohl(--(*msg_x_id)); +	if ((! XDR_PUTBYTES(xdrs, ct->ct_mcall, ct->ct_mpos)) || +	    (! XDR_PUTLONG(xdrs, (long *)&proc)) || +	    (! AUTH_MARSHALL(h->cl_auth, xdrs)) || +	    (! (*xdr_args)(xdrs, args_ptr))) { +		if (ct->ct_error.re_status == RPC_SUCCESS) +			ct->ct_error.re_status = RPC_CANTENCODEARGS; +		(void)xdrrec_endofrecord(xdrs, TRUE); +		return (ct->ct_error.re_status); +	} +	if (! xdrrec_endofrecord(xdrs, shipnow)) +		return (ct->ct_error.re_status = RPC_CANTSEND); +	if (! shipnow) +		return (RPC_SUCCESS); +	/* +	 * Hack to provide rpc-based message passing +	 */ +	if (timeout.tv_sec == 0 && timeout.tv_usec == 0) { +		return(ct->ct_error.re_status = RPC_TIMEDOUT); +	} + + +	/* +	 * Keep receiving until we get a valid transaction id +	 */ +	xdrs->x_op = XDR_DECODE; +	while (TRUE) { +		reply_msg.acpted_rply.ar_verf = _null_auth; +		reply_msg.acpted_rply.ar_results.where = NULL; +		reply_msg.acpted_rply.ar_results.proc = xdr_void; +		if (! xdrrec_skiprecord(xdrs)) +			return (ct->ct_error.re_status); +		/* now decode and validate the response header */ +		if (! xdr_replymsg(xdrs, &reply_msg)) { +			if (ct->ct_error.re_status == RPC_SUCCESS) +				continue; +			return (ct->ct_error.re_status); +		} +		if (reply_msg.rm_xid == x_id) +			break; +	} + +	/* +	 * process header +	 */ +	_seterr_reply(&reply_msg, &(ct->ct_error)); +	if (ct->ct_error.re_status == RPC_SUCCESS) { +		if (! AUTH_VALIDATE(h->cl_auth, &reply_msg.acpted_rply.ar_verf)) { +			ct->ct_error.re_status = RPC_AUTHERROR; +			ct->ct_error.re_why = AUTH_INVALIDRESP; +		} else if (! (*xdr_results)(xdrs, results_ptr)) { +			if (ct->ct_error.re_status == RPC_SUCCESS) +				ct->ct_error.re_status = RPC_CANTDECODERES; +		} +		/* free verifier ... */ +		if (reply_msg.acpted_rply.ar_verf.oa_base != NULL) { +			xdrs->x_op = XDR_FREE; +			(void)xdr_opaque_auth(xdrs, &(reply_msg.acpted_rply.ar_verf)); +		} +	}  /* end successful completion */ +	else { +		/* maybe our credentials need to be refreshed ... */ +		if (refreshes-- && AUTH_REFRESH(h->cl_auth)) +			goto call_again; +	}  /* end of unsuccessful completion */ +	return (ct->ct_error.re_status); +} + +static void +clnttcp_geterr(h, errp) +	CLIENT *h; +	struct rpc_err *errp; +{ +	register struct ct_data *ct = +	    (struct ct_data *) h->cl_private; + +	*errp = ct->ct_error; +} + +static bool_t +clnttcp_freeres(cl, xdr_res, res_ptr) +	CLIENT *cl; +	xdrproc_t xdr_res; +	caddr_t res_ptr; +{ +	register struct ct_data *ct = (struct ct_data *)cl->cl_private; +	register XDR *xdrs = &(ct->ct_xdrs); + +	xdrs->x_op = XDR_FREE; +	return ((*xdr_res)(xdrs, res_ptr)); +} + +static void +clnttcp_abort() +{ +} + +static bool_t +clnttcp_control(cl, request, info) +	CLIENT *cl; +	int request; +	char *info; +{ +	register struct ct_data *ct = (struct ct_data *)cl->cl_private; + +	switch (request) { +	case CLSET_TIMEOUT: +		ct->ct_wait = *(struct timeval *)info; +		ct->ct_waitset = TRUE; +		break; +	case CLGET_TIMEOUT: +		*(struct timeval *)info = ct->ct_wait; +		break; +	case CLGET_SERVER_ADDR: +		*(struct sockaddr_in *)info = ct->ct_addr; +		break; +	default: +		return (FALSE); +	} +	return (TRUE); +} + + +static void +clnttcp_destroy(h) +	CLIENT *h; +{ +	register struct ct_data *ct = +	    (struct ct_data *) h->cl_private; + +	if (ct->ct_closeit) { +		(void)close(ct->ct_sock); +	} +	XDR_DESTROY(&(ct->ct_xdrs)); +	mem_free((caddr_t)ct, sizeof(struct ct_data)); +	mem_free((caddr_t)h, sizeof(CLIENT)); +} + +/* + * Interface between xdr serializer and tcp connection. + * Behaves like the system calls, read & write, but keeps some error state + * around for the rpc level. + */ +static int +readtcp(ct, buf, len) +	register struct ct_data *ct; +	caddr_t buf; +	register int len; +{ +#ifdef FD_SETSIZE +	fd_set mask; +	fd_set readfds; + +	if (len == 0) +		return (0); +	FD_ZERO(&mask); +	FD_SET(ct->ct_sock, &mask); +#else +	register int mask = 1 << (ct->ct_sock); +	int readfds; + +	if (len == 0) +		return (0); + +#endif /* def FD_SETSIZE */ +	while (TRUE) { +		readfds = mask; +		switch (select(_rpc_dtablesize(), &readfds, (int*)NULL, (int*)NULL, +			       &(ct->ct_wait))) { +		case 0: +			ct->ct_error.re_status = RPC_TIMEDOUT; +			return (-1); + +		case -1: +			if (errno == EINTR) +				continue; +			ct->ct_error.re_status = RPC_CANTRECV; +			ct->ct_error.re_errno = errno; +			return (-1); +		} +		break; +	} +	switch (len = read(ct->ct_sock, buf, len)) { + +	case 0: +		/* premature eof */ +		ct->ct_error.re_errno = ECONNRESET; +		ct->ct_error.re_status = RPC_CANTRECV; +		len = -1;  /* it's really an error */ +		break; + +	case -1: +		ct->ct_error.re_errno = errno; +		ct->ct_error.re_status = RPC_CANTRECV; +		break; +	} +	return (len); +} + +static int +writetcp(ct, buf, len) +	struct ct_data *ct; +	caddr_t buf; +	int len; +{ +	register int i, cnt; + +	for (cnt = len; cnt > 0; cnt -= i, buf += i) { +		if ((i = write(ct->ct_sock, buf, cnt)) == -1) { +			ct->ct_error.re_errno = errno; +			ct->ct_error.re_status = RPC_CANTSEND; +			return (-1); +		} +	} +	return (len); +} diff --git a/lib/librpc/rpc/clnt_udp.c b/lib/librpc/rpc/clnt_udp.c new file mode 100644 index 000000000000..815cbb4ed269 --- /dev/null +++ b/lib/librpc/rpc/clnt_udp.c @@ -0,0 +1,442 @@ +/* @(#)clnt_udp.c	2.2 88/08/01 4.0 RPCSRC */ +/* + * Sun RPC is a product of Sun Microsystems, Inc. and is provided for + * unrestricted use provided that this legend is included on all tape + * media and as a part of the software program in whole or part.  Users + * may copy or modify Sun RPC without charge, but are not authorized + * to license or distribute it to anyone else except as part of a product or + * program developed by the user. + *  + * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE + * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR + * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. + *  + * Sun RPC is provided with no support and without any obligation on the + * part of Sun Microsystems, Inc. to assist in its use, correction, + * modification or enhancement. + *  + * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE + * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC + * OR ANY PART THEREOF. + *  + * In no event will Sun Microsystems, Inc. be liable for any lost revenue + * or profits or other special, indirect and consequential damages, even if + * Sun has been advised of the possibility of such damages. + *  + * Sun Microsystems, Inc. + * 2550 Garcia Avenue + * Mountain View, California  94043 + */ +#if !defined(lint) && defined(SCCSIDS) +static char sccsid[] = "@(#)clnt_udp.c 1.39 87/08/11 Copyr 1984 Sun Micro"; +#endif + +/* + * clnt_udp.c, Implements a UDP/IP based, client side RPC. + * + * Copyright (C) 1984, Sun Microsystems, Inc. + */ + +#include <stdio.h> +#include <rpc/rpc.h> +#include <sys/socket.h> +#include <sys/ioctl.h> +#include <netdb.h> +#include <errno.h> +#include <rpc/pmap_clnt.h> + +extern int errno; + +/* + * UDP bases client side rpc operations + */ +static enum clnt_stat	clntudp_call(); +static void		clntudp_abort(); +static void		clntudp_geterr(); +static bool_t		clntudp_freeres(); +static bool_t           clntudp_control(); +static void		clntudp_destroy(); + +static struct clnt_ops udp_ops = { +	clntudp_call, +	clntudp_abort, +	clntudp_geterr, +	clntudp_freeres, +	clntudp_destroy, +	clntudp_control +}; + +/*  + * Private data kept per client handle + */ +struct cu_data { +	int		   cu_sock; +	bool_t		   cu_closeit; +	struct sockaddr_in cu_raddr; +	int		   cu_rlen; +	struct timeval	   cu_wait; +	struct timeval     cu_total; +	struct rpc_err	   cu_error; +	XDR		   cu_outxdrs; +	u_int		   cu_xdrpos; +	u_int		   cu_sendsz; +	char		   *cu_outbuf; +	u_int		   cu_recvsz; +	char		   cu_inbuf[1]; +}; + +/* + * Create a UDP based client handle. + * If *sockp<0, *sockp is set to a newly created UPD socket. + * If raddr->sin_port is 0 a binder on the remote machine + * is consulted for the correct port number. + * NB: It is the clients responsibility to close *sockp. + * NB: The rpch->cl_auth is initialized to null authentication. + *     Caller may wish to set this something more useful. + * + * wait is the amount of time used between retransmitting a call if + * no response has been heard;  retransmition occurs until the actual + * rpc call times out. + * + * sendsz and recvsz are the maximum allowable packet sizes that can be + * sent and received. + */ +CLIENT * +clntudp_bufcreate(raddr, program, version, wait, sockp, sendsz, recvsz) +	struct sockaddr_in *raddr; +	u_long program; +	u_long version; +	struct timeval wait; +	register int *sockp; +	u_int sendsz; +	u_int recvsz; +{ +	CLIENT *cl; +	register struct cu_data *cu; +	struct timeval now; +	struct rpc_msg call_msg; + +	cl = (CLIENT *)mem_alloc(sizeof(CLIENT)); +	if (cl == NULL) { +		(void) fprintf(stderr, "clntudp_create: out of memory\n"); +		rpc_createerr.cf_stat = RPC_SYSTEMERROR; +		rpc_createerr.cf_error.re_errno = errno; +		goto fooy; +	} +	sendsz = ((sendsz + 3) / 4) * 4; +	recvsz = ((recvsz + 3) / 4) * 4; +	cu = (struct cu_data *)mem_alloc(sizeof(*cu) + sendsz + recvsz); +	if (cu == NULL) { +		(void) fprintf(stderr, "clntudp_create: out of memory\n"); +		rpc_createerr.cf_stat = RPC_SYSTEMERROR; +		rpc_createerr.cf_error.re_errno = errno; +		goto fooy; +	} +	cu->cu_outbuf = &cu->cu_inbuf[recvsz]; + +	(void)gettimeofday(&now, (struct timezone *)0); +	if (raddr->sin_port == 0) { +		u_short port; +		if ((port = +		    pmap_getport(raddr, program, version, IPPROTO_UDP)) == 0) { +			goto fooy; +		} +		raddr->sin_port = htons(port); +	} +	cl->cl_ops = &udp_ops; +	cl->cl_private = (caddr_t)cu; +	cu->cu_raddr = *raddr; +	cu->cu_rlen = sizeof (cu->cu_raddr); +	cu->cu_wait = wait; +	cu->cu_total.tv_sec = -1; +	cu->cu_total.tv_usec = -1; +	cu->cu_sendsz = sendsz; +	cu->cu_recvsz = recvsz; +	call_msg.rm_xid = getpid() ^ now.tv_sec ^ now.tv_usec; +	call_msg.rm_direction = CALL; +	call_msg.rm_call.cb_rpcvers = RPC_MSG_VERSION; +	call_msg.rm_call.cb_prog = program; +	call_msg.rm_call.cb_vers = version; +	xdrmem_create(&(cu->cu_outxdrs), cu->cu_outbuf, +	    sendsz, XDR_ENCODE); +	if (! xdr_callhdr(&(cu->cu_outxdrs), &call_msg)) { +		goto fooy; +	} +	cu->cu_xdrpos = XDR_GETPOS(&(cu->cu_outxdrs)); +	if (*sockp < 0) { +		int dontblock = 1; + +		*sockp = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); +		if (*sockp < 0) { +			rpc_createerr.cf_stat = RPC_SYSTEMERROR; +			rpc_createerr.cf_error.re_errno = errno; +			goto fooy; +		} +		/* attempt to bind to prov port */ +		(void)bindresvport(*sockp, (struct sockaddr_in *)0); +		/* the sockets rpc controls are non-blocking */ +		(void)ioctl(*sockp, FIONBIO, (char *) &dontblock); +		cu->cu_closeit = TRUE; +	} else { +		cu->cu_closeit = FALSE; +	} +	cu->cu_sock = *sockp; +	cl->cl_auth = authnone_create(); +	return (cl); +fooy: +	if (cu) +		mem_free((caddr_t)cu, sizeof(*cu) + sendsz + recvsz); +	if (cl) +		mem_free((caddr_t)cl, sizeof(CLIENT)); +	return ((CLIENT *)NULL); +} + +CLIENT * +clntudp_create(raddr, program, version, wait, sockp) +	struct sockaddr_in *raddr; +	u_long program; +	u_long version; +	struct timeval wait; +	register int *sockp; +{ + +	return(clntudp_bufcreate(raddr, program, version, wait, sockp, +	    UDPMSGSIZE, UDPMSGSIZE)); +} + +static enum clnt_stat  +clntudp_call(cl, proc, xargs, argsp, xresults, resultsp, utimeout) +	register CLIENT	*cl;		/* client handle */ +	u_long		proc;		/* procedure number */ +	xdrproc_t	xargs;		/* xdr routine for args */ +	caddr_t		argsp;		/* pointer to args */ +	xdrproc_t	xresults;	/* xdr routine for results */ +	caddr_t		resultsp;	/* pointer to results */ +	struct timeval	utimeout;	/* seconds to wait before giving up */ +{ +	register struct cu_data *cu = (struct cu_data *)cl->cl_private; +	register XDR *xdrs; +	register int outlen; +	register int inlen; +	int fromlen; +#ifdef FD_SETSIZE +	fd_set readfds; +	fd_set mask; +#else +	int readfds; +	register int mask; +#endif /* def FD_SETSIZE */ +	struct sockaddr_in from; +	struct rpc_msg reply_msg; +	XDR reply_xdrs; +	struct timeval time_waited; +	bool_t ok; +	int nrefreshes = 2;	/* number of times to refresh cred */ +	struct timeval timeout; + +	if (cu->cu_total.tv_usec == -1) { +		timeout = utimeout;     /* use supplied timeout */ +	} else { +		timeout = cu->cu_total; /* use default timeout */ +	} + +	time_waited.tv_sec = 0; +	time_waited.tv_usec = 0; +call_again: +	xdrs = &(cu->cu_outxdrs); +	xdrs->x_op = XDR_ENCODE; +	XDR_SETPOS(xdrs, cu->cu_xdrpos); +	/* +	 * the transaction is the first thing in the out buffer +	 */ +	(*(u_short *)(cu->cu_outbuf))++; +	if ((! XDR_PUTLONG(xdrs, (long *)&proc)) || +	    (! AUTH_MARSHALL(cl->cl_auth, xdrs)) || +	    (! (*xargs)(xdrs, argsp))) +		return (cu->cu_error.re_status = RPC_CANTENCODEARGS); +	outlen = (int)XDR_GETPOS(xdrs); + +send_again: +	if (sendto(cu->cu_sock, cu->cu_outbuf, outlen, 0, +	    (struct sockaddr *)&(cu->cu_raddr), cu->cu_rlen) +	    != outlen) { +		cu->cu_error.re_errno = errno; +		return (cu->cu_error.re_status = RPC_CANTSEND); +	} + +	/* +	 * Hack to provide rpc-based message passing +	 */ +	if (timeout.tv_sec == 0 && timeout.tv_usec == 0) { +		return (cu->cu_error.re_status = RPC_TIMEDOUT); +	} +	/* +	 * sub-optimal code appears here because we have +	 * some clock time to spare while the packets are in flight. +	 * (We assume that this is actually only executed once.) +	 */ +	reply_msg.acpted_rply.ar_verf = _null_auth; +	reply_msg.acpted_rply.ar_results.where = resultsp; +	reply_msg.acpted_rply.ar_results.proc = xresults; +#ifdef FD_SETSIZE +	FD_ZERO(&mask); +	FD_SET(cu->cu_sock, &mask); +#else +	mask = 1 << cu->cu_sock; +#endif /* def FD_SETSIZE */ +	for (;;) { +		readfds = mask; +		switch (select(_rpc_dtablesize(), &readfds, (int *)NULL,  +			       (int *)NULL, &(cu->cu_wait))) { + +		case 0: +			time_waited.tv_sec += cu->cu_wait.tv_sec; +			time_waited.tv_usec += cu->cu_wait.tv_usec; +			while (time_waited.tv_usec >= 1000000) { +				time_waited.tv_sec++; +				time_waited.tv_usec -= 1000000; +			} +			if ((time_waited.tv_sec < timeout.tv_sec) || +				((time_waited.tv_sec == timeout.tv_sec) && +				(time_waited.tv_usec < timeout.tv_usec))) +				goto send_again;	 +			return (cu->cu_error.re_status = RPC_TIMEDOUT); + +		/* +		 * buggy in other cases because time_waited is not being +		 * updated. +		 */ +		case -1: +			if (errno == EINTR) +				continue;	 +			cu->cu_error.re_errno = errno; +			return (cu->cu_error.re_status = RPC_CANTRECV); +		} +		do { +			fromlen = sizeof(struct sockaddr); +			inlen = recvfrom(cu->cu_sock, cu->cu_inbuf,  +				(int) cu->cu_recvsz, 0, +				(struct sockaddr *)&from, &fromlen); +		} while (inlen < 0 && errno == EINTR); +		if (inlen < 0) { +			if (errno == EWOULDBLOCK) +				continue;	 +			cu->cu_error.re_errno = errno; +			return (cu->cu_error.re_status = RPC_CANTRECV); +		} +		if (inlen < sizeof(u_long)) +			continue;	 +		/* see if reply transaction id matches sent id */ +		if (*((u_long *)(cu->cu_inbuf)) != *((u_long *)(cu->cu_outbuf))) +			continue;	 +		/* we now assume we have the proper reply */ +		break; +	} + +	/* +	 * now decode and validate the response +	 */ +	xdrmem_create(&reply_xdrs, cu->cu_inbuf, (u_int)inlen, XDR_DECODE); +	ok = xdr_replymsg(&reply_xdrs, &reply_msg); +	/* XDR_DESTROY(&reply_xdrs);  save a few cycles on noop destroy */ +	if (ok) { +		_seterr_reply(&reply_msg, &(cu->cu_error)); +		if (cu->cu_error.re_status == RPC_SUCCESS) { +			if (! AUTH_VALIDATE(cl->cl_auth, +				&reply_msg.acpted_rply.ar_verf)) { +				cu->cu_error.re_status = RPC_AUTHERROR; +				cu->cu_error.re_why = AUTH_INVALIDRESP; +			} +			if (reply_msg.acpted_rply.ar_verf.oa_base != NULL) { +				xdrs->x_op = XDR_FREE; +				(void)xdr_opaque_auth(xdrs, +				    &(reply_msg.acpted_rply.ar_verf)); +			}  +		}  /* end successful completion */ +		else { +			/* maybe our credentials need to be refreshed ... */ +			if (nrefreshes > 0 && AUTH_REFRESH(cl->cl_auth)) { +				nrefreshes--; +				goto call_again; +			} +		}  /* end of unsuccessful completion */ +	}  /* end of valid reply message */ +	else { +		cu->cu_error.re_status = RPC_CANTDECODERES; +	} +	return (cu->cu_error.re_status); +} + +static void +clntudp_geterr(cl, errp) +	CLIENT *cl; +	struct rpc_err *errp; +{ +	register struct cu_data *cu = (struct cu_data *)cl->cl_private; + +	*errp = cu->cu_error; +} + + +static bool_t +clntudp_freeres(cl, xdr_res, res_ptr) +	CLIENT *cl; +	xdrproc_t xdr_res; +	caddr_t res_ptr; +{ +	register struct cu_data *cu = (struct cu_data *)cl->cl_private; +	register XDR *xdrs = &(cu->cu_outxdrs); + +	xdrs->x_op = XDR_FREE; +	return ((*xdr_res)(xdrs, res_ptr)); +} + +static void  +clntudp_abort(/*h*/) +	/*CLIENT *h;*/ +{ +} + +static bool_t +clntudp_control(cl, request, info) +	CLIENT *cl; +	int request; +	char *info; +{ +	register struct cu_data *cu = (struct cu_data *)cl->cl_private; + +	switch (request) { +	case CLSET_TIMEOUT: +		cu->cu_total = *(struct timeval *)info; +		break; +	case CLGET_TIMEOUT: +		*(struct timeval *)info = cu->cu_total; +		break; +	case CLSET_RETRY_TIMEOUT: +		cu->cu_wait = *(struct timeval *)info; +		break; +	case CLGET_RETRY_TIMEOUT: +		*(struct timeval *)info = cu->cu_wait; +		break; +	case CLGET_SERVER_ADDR: +		*(struct sockaddr_in *)info = cu->cu_raddr; +		break; +	default: +		return (FALSE); +	} +	return (TRUE); +} +	 +static void +clntudp_destroy(cl) +	CLIENT *cl; +{ +	register struct cu_data *cu = (struct cu_data *)cl->cl_private; + +	if (cu->cu_closeit) { +		(void)close(cu->cu_sock); +	} +	XDR_DESTROY(&(cu->cu_outxdrs)); +	mem_free((caddr_t)cu, (sizeof(*cu) + cu->cu_sendsz + cu->cu_recvsz)); +	mem_free((caddr_t)cl, sizeof(CLIENT)); +} diff --git a/lib/librpc/rpc/get_myaddress.c b/lib/librpc/rpc/get_myaddress.c new file mode 100644 index 000000000000..60b12272c4f5 --- /dev/null +++ b/lib/librpc/rpc/get_myaddress.c @@ -0,0 +1,96 @@ +/* @(#)get_myaddress.c	2.1 88/07/29 4.0 RPCSRC */ +/* + * Sun RPC is a product of Sun Microsystems, Inc. and is provided for + * unrestricted use provided that this legend is included on all tape + * media and as a part of the software program in whole or part.  Users + * may copy or modify Sun RPC without charge, but are not authorized + * to license or distribute it to anyone else except as part of a product or + * program developed by the user. + *  + * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE + * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR + * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. + *  + * Sun RPC is provided with no support and without any obligation on the + * part of Sun Microsystems, Inc. to assist in its use, correction, + * modification or enhancement. + *  + * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE + * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC + * OR ANY PART THEREOF. + *  + * In no event will Sun Microsystems, Inc. be liable for any lost revenue + * or profits or other special, indirect and consequential damages, even if + * Sun has been advised of the possibility of such damages. + *  + * Sun Microsystems, Inc. + * 2550 Garcia Avenue + * Mountain View, California  94043 + */ +#if !defined(lint) && defined(SCCSIDS) +static char sccsid[] = "@(#)get_myaddress.c 1.4 87/08/11 Copyr 1984 Sun Micro"; +#endif + +/* + * get_myaddress.c + * + * Get client's IP address via ioctl.  This avoids using the yellowpages. + * Copyright (C) 1984, Sun Microsystems, Inc. + */ + +#include <rpc/types.h> +#include <rpc/pmap_prot.h> +#include <sys/socket.h> +#include <stdio.h> +#include <net/if.h> +#include <sys/ioctl.h> +#include <netinet/in.h> +#include <arpa/inet.h> + +/*  + * don't use gethostbyname, which would invoke yellow pages + */ +get_myaddress(addr) +	struct sockaddr_in *addr; +{ +	int s; +	char buf[BUFSIZ]; +	struct ifconf ifc; +	struct ifreq ifreq, *ifr; +	int len, slop; + +	if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { +	    perror("get_myaddress: socket"); +	    exit(1); +	} +	ifc.ifc_len = sizeof (buf); +	ifc.ifc_buf = buf; +	if (ioctl(s, SIOCGIFCONF, (char *)&ifc) < 0) { +		perror("get_myaddress: ioctl (get interface configuration)"); +		exit(1); +	} +	ifr = ifc.ifc_req; +	for (len = ifc.ifc_len; len; len -= sizeof ifreq) { +		ifreq = *ifr; +		if (ioctl(s, SIOCGIFFLAGS, (char *)&ifreq) < 0) { +			perror("get_myaddress: ioctl"); +			exit(1); +		} +		if ((ifreq.ifr_flags & IFF_UP) && +		    ifr->ifr_addr.sa_family == AF_INET) { +			*addr = *((struct sockaddr_in *)&ifr->ifr_addr); +			addr->sin_port = htons(PMAPPORT); +			break; +		} +		/* +		 * Deal with variable length addresses +		 */ +		slop = ifr->ifr_addr.sa_len - sizeof (struct sockaddr); +		if (slop) { +			ifr = (struct ifreq *) ((caddr_t)ifr + slop); +			len -= slop; +		} +		ifr++; +	} +	(void) close(s); +} diff --git a/lib/librpc/rpc/getrpcent.c b/lib/librpc/rpc/getrpcent.c new file mode 100644 index 000000000000..e103546054f1 --- /dev/null +++ b/lib/librpc/rpc/getrpcent.c @@ -0,0 +1,235 @@ +/* @(#)getrpcent.c	2.2 88/07/29 4.0 RPCSRC */ +#if !defined(lint) && defined(SCCSIDS) +static  char sccsid[] = "@(#)getrpcent.c 1.9 87/08/11  Copyr 1984 Sun Micro"; +#endif + +/* + * Sun RPC is a product of Sun Microsystems, Inc. and is provided for + * unrestricted use provided that this legend is included on all tape + * media and as a part of the software program in whole or part.  Users + * may copy or modify Sun RPC without charge, but are not authorized + * to license or distribute it to anyone else except as part of a product or + * program developed by the user. + *  + * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE + * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR + * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. + *  + * Sun RPC is provided with no support and without any obligation on the + * part of Sun Microsystems, Inc. to assist in its use, correction, + * modification or enhancement. + *  + * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE + * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC + * OR ANY PART THEREOF. + *  + * In no event will Sun Microsystems, Inc. be liable for any lost revenue + * or profits or other special, indirect and consequential damages, even if + * Sun has been advised of the possibility of such damages. + *  + * Sun Microsystems, Inc. + * 2550 Garcia Avenue + * Mountain View, California  94043 + */ + +/* + * Copyright (c) 1985 by Sun Microsystems, Inc. + */ + +#include <stdio.h> +#include <sys/types.h> +#include <rpc/rpc.h> +#include <netdb.h> +#include <sys/socket.h> + +/* + * Internet version. + */ +struct rpcdata { +	FILE	*rpcf; +	char	*current; +	int	currentlen; +	int	stayopen; +#define	MAXALIASES	35 +	char	*rpc_aliases[MAXALIASES]; +	struct	rpcent rpc; +	char	line[BUFSIZ+1]; +	char	*domain; +} *rpcdata; + +static	struct rpcent *interpret(); +struct	hostent *gethostent(); +char	*inet_ntoa(); +char	*index(); + +static char RPCDB[] = "/etc/rpc"; + +static struct rpcdata * +_rpcdata() +{ +	register struct rpcdata *d = rpcdata; + +	if (d == 0) { +		d = (struct rpcdata *)calloc(1, sizeof (struct rpcdata)); +		rpcdata = d; +	} +	return (d); +} + +struct rpcent * +getrpcbynumber(number) +	register int number; +{ +	register struct rpcdata *d = _rpcdata(); +	register struct rpcent *p; +	int reason; +	char adrstr[16], *val = NULL; +	int vallen; + +	if (d == 0) +		return (0); +	setrpcent(0); +	while (p = getrpcent()) { +		if (p->r_number == number) +			break; +	} +	endrpcent(); +	return (p); +} + +struct rpcent * +getrpcbyname(name) +	char *name; +{ +	struct rpcent *rpc; +	char **rp; + +	setrpcent(0); +	while(rpc = getrpcent()) { +		if (strcmp(rpc->r_name, name) == 0) +			return (rpc); +		for (rp = rpc->r_aliases; *rp != NULL; rp++) { +			if (strcmp(*rp, name) == 0) +				return (rpc); +		} +	} +	endrpcent(); +	return (NULL); +} + +setrpcent(f) +	int f; +{ +	register struct rpcdata *d = _rpcdata(); + +	if (d == 0) +		return; +	if (d->rpcf == NULL) +		d->rpcf = fopen(RPCDB, "r"); +	else +		rewind(d->rpcf); +	if (d->current) +		free(d->current); +	d->current = NULL; +	d->stayopen |= f; +} + +endrpcent() +{ +	register struct rpcdata *d = _rpcdata(); + +	if (d == 0) +		return; +	if (d->current && !d->stayopen) { +		free(d->current); +		d->current = NULL; +	} +	if (d->rpcf && !d->stayopen) { +		fclose(d->rpcf); +		d->rpcf = NULL; +	} +} + +struct rpcent * +getrpcent() +{ +	struct rpcent *hp; +	int reason; +	char *key = NULL, *val = NULL; +	int keylen, vallen; +	register struct rpcdata *d = _rpcdata(); + +	if (d == 0) +		return(NULL); +	if (d->rpcf == NULL && (d->rpcf = fopen(RPCDB, "r")) == NULL) +		return (NULL); +    if (fgets(d->line, BUFSIZ, d->rpcf) == NULL) +		return (NULL); +	return interpret(d->line, strlen(d->line)); +} + +static struct rpcent * +interpret(val, len) +{ +	register struct rpcdata *d = _rpcdata(); +	char *p; +	register char *cp, **q; + +	if (d == 0) +		return; +	strncpy(d->line, val, len); +	p = d->line; +	d->line[len] = '\n'; +	if (*p == '#') +		return (getrpcent()); +	cp = index(p, '#'); +	if (cp == NULL) +    { +		cp = index(p, '\n'); +		if (cp == NULL) +			return (getrpcent()); +	} +	*cp = '\0'; +	cp = index(p, ' '); +	if (cp == NULL) +    { +		cp = index(p, '\t'); +		if (cp == NULL) +			return (getrpcent()); +	} +	*cp++ = '\0'; +	/* THIS STUFF IS INTERNET SPECIFIC */ +	d->rpc.r_name = d->line; +	while (*cp == ' ' || *cp == '\t') +		cp++; +	d->rpc.r_number = atoi(cp); +	q = d->rpc.r_aliases = d->rpc_aliases; +	cp = index(p, ' '); +	if (cp != NULL) +		*cp++ = '\0'; +	else +    { +		cp = index(p, '\t'); +		if (cp != NULL) +			*cp++ = '\0'; +	} +	while (cp && *cp) { +		if (*cp == ' ' || *cp == '\t') { +			cp++; +			continue; +		} +		if (q < &(d->rpc_aliases[MAXALIASES - 1])) +			*q++ = cp; +		cp = index(p, ' '); +		if (cp != NULL) +			*cp++ = '\0'; +		else +	    { +			cp = index(p, '\t'); +			if (cp != NULL) +				*cp++ = '\0'; +		} +	} +	*q = NULL; +	return (&d->rpc); +} diff --git a/lib/librpc/rpc/getrpcport.c b/lib/librpc/rpc/getrpcport.c new file mode 100644 index 000000000000..9b13bac6b010 --- /dev/null +++ b/lib/librpc/rpc/getrpcport.c @@ -0,0 +1,55 @@ +/* @(#)getrpcport.c	2.1 88/07/29 4.0 RPCSRC */ +#if !defined(lint) && defined(SCCSIDS) +static  char sccsid[] = "@(#)getrpcport.c 1.3 87/08/11 SMI"; +#endif +/* + * Sun RPC is a product of Sun Microsystems, Inc. and is provided for + * unrestricted use provided that this legend is included on all tape + * media and as a part of the software program in whole or part.  Users + * may copy or modify Sun RPC without charge, but are not authorized + * to license or distribute it to anyone else except as part of a product or + * program developed by the user. + *  + * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE + * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR + * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. + *  + * Sun RPC is provided with no support and without any obligation on the + * part of Sun Microsystems, Inc. to assist in its use, correction, + * modification or enhancement. + *  + * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE + * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC + * OR ANY PART THEREOF. + *  + * In no event will Sun Microsystems, Inc. be liable for any lost revenue + * or profits or other special, indirect and consequential damages, even if + * Sun has been advised of the possibility of such damages. + *  + * Sun Microsystems, Inc. + * 2550 Garcia Avenue + * Mountain View, California  94043 + */ + +/* + * Copyright (c) 1985 by Sun Microsystems, Inc. + */ + +#include <stdio.h> +#include <rpc/rpc.h> +#include <netdb.h> +#include <sys/socket.h> + +getrpcport(host, prognum, versnum, proto) +	char *host; +{ +	struct sockaddr_in addr; +	struct hostent *hp; + +	if ((hp = gethostbyname(host)) == NULL) +		return (0); +	bcopy(hp->h_addr, (char *) &addr.sin_addr, hp->h_length); +	addr.sin_family = AF_INET; +	addr.sin_port =  0; +	return (pmap_getport(&addr, prognum, versnum, proto)); +} diff --git a/lib/librpc/rpc/pmap_clnt.c b/lib/librpc/rpc/pmap_clnt.c new file mode 100644 index 000000000000..09220e77b1fe --- /dev/null +++ b/lib/librpc/rpc/pmap_clnt.c @@ -0,0 +1,115 @@ +/* @(#)pmap_clnt.c	2.2 88/08/01 4.0 RPCSRC */ +/* + * Sun RPC is a product of Sun Microsystems, Inc. and is provided for + * unrestricted use provided that this legend is included on all tape + * media and as a part of the software program in whole or part.  Users + * may copy or modify Sun RPC without charge, but are not authorized + * to license or distribute it to anyone else except as part of a product or + * program developed by the user. + *  + * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE + * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR + * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. + *  + * Sun RPC is provided with no support and without any obligation on the + * part of Sun Microsystems, Inc. to assist in its use, correction, + * modification or enhancement. + *  + * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE + * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC + * OR ANY PART THEREOF. + *  + * In no event will Sun Microsystems, Inc. be liable for any lost revenue + * or profits or other special, indirect and consequential damages, even if + * Sun has been advised of the possibility of such damages. + *  + * Sun Microsystems, Inc. + * 2550 Garcia Avenue + * Mountain View, California  94043 + */ +#if !defined(lint) && defined(SCCSIDS) +static char sccsid[] = "@(#)pmap_clnt.c 1.37 87/08/11 Copyr 1984 Sun Micro"; +#endif + +/* + * pmap_clnt.c + * Client interface to pmap rpc service. + * + * Copyright (C) 1984, Sun Microsystems, Inc. + */ + +#include <rpc/rpc.h> +#include <rpc/pmap_prot.h> +#include <rpc/pmap_clnt.h> + +static struct timeval timeout = { 5, 0 }; +static struct timeval tottimeout = { 60, 0 }; + +void clnt_perror(); + + +/* + * Set a mapping between program,version and port. + * Calls the pmap service remotely to do the mapping. + */ +bool_t +pmap_set(program, version, protocol, port) +	u_long program; +	u_long version; +	int protocol; +	u_short port; +{ +	struct sockaddr_in myaddress; +	int socket = -1; +	register CLIENT *client; +	struct pmap parms; +	bool_t rslt; + +	get_myaddress(&myaddress); +	client = clntudp_bufcreate(&myaddress, PMAPPROG, PMAPVERS, +	    timeout, &socket, RPCSMALLMSGSIZE, RPCSMALLMSGSIZE); +	if (client == (CLIENT *)NULL) +		return (FALSE); +	parms.pm_prog = program; +	parms.pm_vers = version; +	parms.pm_prot = protocol; +	parms.pm_port = port; +	if (CLNT_CALL(client, PMAPPROC_SET, xdr_pmap, &parms, xdr_bool, &rslt, +	    tottimeout) != RPC_SUCCESS) { +		clnt_perror(client, "Cannot register service"); +		return (FALSE); +	} +	CLNT_DESTROY(client); +	(void)close(socket); +	return (rslt); +} + +/* + * Remove the mapping between program,version and port. + * Calls the pmap service remotely to do the un-mapping. + */ +bool_t +pmap_unset(program, version) +	u_long program; +	u_long version; +{ +	struct sockaddr_in myaddress; +	int socket = -1; +	register CLIENT *client; +	struct pmap parms; +	bool_t rslt; + +	get_myaddress(&myaddress); +	client = clntudp_bufcreate(&myaddress, PMAPPROG, PMAPVERS, +	    timeout, &socket, RPCSMALLMSGSIZE, RPCSMALLMSGSIZE); +	if (client == (CLIENT *)NULL) +		return (FALSE); +	parms.pm_prog = program; +	parms.pm_vers = version; +	parms.pm_port = parms.pm_prot = 0; +	CLNT_CALL(client, PMAPPROC_UNSET, xdr_pmap, &parms, xdr_bool, &rslt, +	    tottimeout); +	CLNT_DESTROY(client); +	(void)close(socket); +	return (rslt); +} diff --git a/lib/librpc/rpc/pmap_clnt.h b/lib/librpc/rpc/pmap_clnt.h new file mode 100644 index 000000000000..d2ea2a88e9e5 --- /dev/null +++ b/lib/librpc/rpc/pmap_clnt.h @@ -0,0 +1,65 @@ +/* @(#)pmap_clnt.h	2.1 88/07/29 4.0 RPCSRC; from 1.11 88/02/08 SMI */ +/* + * Sun RPC is a product of Sun Microsystems, Inc. and is provided for + * unrestricted use provided that this legend is included on all tape + * media and as a part of the software program in whole or part.  Users + * may copy or modify Sun RPC without charge, but are not authorized + * to license or distribute it to anyone else except as part of a product or + * program developed by the user. + *  + * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE + * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR + * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. + *  + * Sun RPC is provided with no support and without any obligation on the + * part of Sun Microsystems, Inc. to assist in its use, correction, + * modification or enhancement. + *  + * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE + * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC + * OR ANY PART THEREOF. + *  + * In no event will Sun Microsystems, Inc. be liable for any lost revenue + * or profits or other special, indirect and consequential damages, even if + * Sun has been advised of the possibility of such damages. + *  + * Sun Microsystems, Inc. + * 2550 Garcia Avenue + * Mountain View, California  94043 + */ + +/* + * pmap_clnt.h + * Supplies C routines to get to portmap services. + * + * Copyright (C) 1984, Sun Microsystems, Inc. + */ + +/* + * Usage: + *	success = pmap_set(program, version, protocol, port); + *	success = pmap_unset(program, version); + *	port = pmap_getport(address, program, version, protocol); + *	head = pmap_getmaps(address); + *	clnt_stat = pmap_rmtcall(address, program, version, procedure, + *		xdrargs, argsp, xdrres, resp, tout, port_ptr) + *		(works for udp only.)  + * 	clnt_stat = clnt_broadcast(program, version, procedure, + *		xdrargs, argsp,	xdrres, resp, eachresult) + *		(like pmap_rmtcall, except the call is broadcasted to all + *		locally connected nets.  For each valid response received, + *		the procedure eachresult is called.  Its form is: + *	done = eachresult(resp, raddr) + *		bool_t done; + *		caddr_t resp; + *		struct sockaddr_in raddr; + *		where resp points to the results of the call and raddr is the + *		address if the responder to the broadcast. + */ + +extern bool_t		pmap_set(); +extern bool_t		pmap_unset(); +extern struct pmaplist	*pmap_getmaps(); +enum clnt_stat		pmap_rmtcall(); +enum clnt_stat		clnt_broadcast(); +extern u_short		pmap_getport(); diff --git a/lib/librpc/rpc/pmap_getmaps.c b/lib/librpc/rpc/pmap_getmaps.c new file mode 100644 index 000000000000..e4a9c49361cf --- /dev/null +++ b/lib/librpc/rpc/pmap_getmaps.c @@ -0,0 +1,84 @@ +/* @(#)pmap_getmaps.c	2.2 88/08/01 4.0 RPCSRC */ +/* + * Sun RPC is a product of Sun Microsystems, Inc. and is provided for + * unrestricted use provided that this legend is included on all tape + * media and as a part of the software program in whole or part.  Users + * may copy or modify Sun RPC without charge, but are not authorized + * to license or distribute it to anyone else except as part of a product or + * program developed by the user. + *  + * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE + * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR + * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. + *  + * Sun RPC is provided with no support and without any obligation on the + * part of Sun Microsystems, Inc. to assist in its use, correction, + * modification or enhancement. + *  + * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE + * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC + * OR ANY PART THEREOF. + *  + * In no event will Sun Microsystems, Inc. be liable for any lost revenue + * or profits or other special, indirect and consequential damages, even if + * Sun has been advised of the possibility of such damages. + *  + * Sun Microsystems, Inc. + * 2550 Garcia Avenue + * Mountain View, California  94043 + */ +#if !defined(lint) && defined(SCCSIDS) +static char sccsid[] = "@(#)pmap_getmaps.c 1.10 87/08/11 Copyr 1984 Sun Micro"; +#endif + +/* + * pmap_getmap.c + * Client interface to pmap rpc service. + * contains pmap_getmaps, which is only tcp service involved + * + * Copyright (C) 1984, Sun Microsystems, Inc. + */ + +#include <rpc/rpc.h> +#include <rpc/pmap_prot.h> +#include <rpc/pmap_clnt.h> +#include <sys/socket.h> +#include <netdb.h> +#include <stdio.h> +#include <errno.h> +#include <net/if.h> +#include <sys/ioctl.h> +#define NAMELEN 255 +#define MAX_BROADCAST_SIZE 1400 + +extern int errno; + +/* + * Get a copy of the current port maps. + * Calls the pmap service remotely to do get the maps. + */ +struct pmaplist * +pmap_getmaps(address) +	 struct sockaddr_in *address; +{ +	struct pmaplist *head = (struct pmaplist *)NULL; +	int socket = -1; +	struct timeval minutetimeout; +	register CLIENT *client; + +	minutetimeout.tv_sec = 60; +	minutetimeout.tv_usec = 0; +	address->sin_port = htons(PMAPPORT); +	client = clnttcp_create(address, PMAPPROG, +	    PMAPVERS, &socket, 50, 500); +	if (client != (CLIENT *)NULL) { +		if (CLNT_CALL(client, PMAPPROC_DUMP, xdr_void, NULL, xdr_pmaplist, +		    &head, minutetimeout) != RPC_SUCCESS) { +			clnt_perror(client, "pmap_getmaps rpc problem"); +		} +		CLNT_DESTROY(client); +	} +	(void)close(socket); +	address->sin_port = 0; +	return (head); +} diff --git a/lib/librpc/rpc/pmap_getport.c b/lib/librpc/rpc/pmap_getport.c new file mode 100644 index 000000000000..77b9cf743ab1 --- /dev/null +++ b/lib/librpc/rpc/pmap_getport.c @@ -0,0 +1,87 @@ +/* @(#)pmap_getport.c	2.2 88/08/01 4.0 RPCSRC */ +/* + * Sun RPC is a product of Sun Microsystems, Inc. and is provided for + * unrestricted use provided that this legend is included on all tape + * media and as a part of the software program in whole or part.  Users + * may copy or modify Sun RPC without charge, but are not authorized + * to license or distribute it to anyone else except as part of a product or + * program developed by the user. + *  + * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE + * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR + * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. + *  + * Sun RPC is provided with no support and without any obligation on the + * part of Sun Microsystems, Inc. to assist in its use, correction, + * modification or enhancement. + *  + * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE + * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC + * OR ANY PART THEREOF. + *  + * In no event will Sun Microsystems, Inc. be liable for any lost revenue + * or profits or other special, indirect and consequential damages, even if + * Sun has been advised of the possibility of such damages. + *  + * Sun Microsystems, Inc. + * 2550 Garcia Avenue + * Mountain View, California  94043 + */ +#if !defined(lint) && defined(SCCSIDS) +static char sccsid[] = "@(#)pmap_getport.c 1.9 87/08/11 Copyr 1984 Sun Micro"; +#endif + +/* + * pmap_getport.c + * Client interface to pmap rpc service. + * + * Copyright (C) 1984, Sun Microsystems, Inc. + */ + +#include <rpc/rpc.h> +#include <rpc/pmap_prot.h> +#include <rpc/pmap_clnt.h> +#include <sys/socket.h> +#include <net/if.h> + +static struct timeval timeout = { 5, 0 }; +static struct timeval tottimeout = { 60, 0 }; + +/* + * Find the mapped port for program,version. + * Calls the pmap service remotely to do the lookup. + * Returns 0 if no map exists. + */ +u_short +pmap_getport(address, program, version, protocol) +	struct sockaddr_in *address; +	u_long program; +	u_long version; +	u_int protocol; +{ +	u_short port = 0; +	int socket = -1; +	register CLIENT *client; +	struct pmap parms; + +	address->sin_port = htons(PMAPPORT); +	client = clntudp_bufcreate(address, PMAPPROG, +	    PMAPVERS, timeout, &socket, RPCSMALLMSGSIZE, RPCSMALLMSGSIZE); +	if (client != (CLIENT *)NULL) { +		parms.pm_prog = program; +		parms.pm_vers = version; +		parms.pm_prot = protocol; +		parms.pm_port = 0;  /* not needed or used */ +		if (CLNT_CALL(client, PMAPPROC_GETPORT, xdr_pmap, &parms, +		    xdr_u_short, &port, tottimeout) != RPC_SUCCESS){ +			rpc_createerr.cf_stat = RPC_PMAPFAILURE; +			clnt_geterr(client, &rpc_createerr.cf_error); +		} else if (port == 0) { +			rpc_createerr.cf_stat = RPC_PROGNOTREGISTERED; +		} +		CLNT_DESTROY(client); +	} +	(void)close(socket); +	address->sin_port = 0; +	return (port); +} diff --git a/lib/librpc/rpc/pmap_prot.c b/lib/librpc/rpc/pmap_prot.c new file mode 100644 index 000000000000..643c2ff6a29c --- /dev/null +++ b/lib/librpc/rpc/pmap_prot.c @@ -0,0 +1,57 @@ +/* @(#)pmap_prot.c	2.1 88/07/29 4.0 RPCSRC */ +/* + * Sun RPC is a product of Sun Microsystems, Inc. and is provided for + * unrestricted use provided that this legend is included on all tape + * media and as a part of the software program in whole or part.  Users + * may copy or modify Sun RPC without charge, but are not authorized + * to license or distribute it to anyone else except as part of a product or + * program developed by the user. + *  + * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE + * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR + * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. + *  + * Sun RPC is provided with no support and without any obligation on the + * part of Sun Microsystems, Inc. to assist in its use, correction, + * modification or enhancement. + *  + * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE + * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC + * OR ANY PART THEREOF. + *  + * In no event will Sun Microsystems, Inc. be liable for any lost revenue + * or profits or other special, indirect and consequential damages, even if + * Sun has been advised of the possibility of such damages. + *  + * Sun Microsystems, Inc. + * 2550 Garcia Avenue + * Mountain View, California  94043 + */ +#if !defined(lint) && defined(SCCSIDS) +static char sccsid[] = "@(#)pmap_prot.c 1.17 87/08/11 Copyr 1984 Sun Micro"; +#endif + +/* + * pmap_prot.c + * Protocol for the local binder service, or pmap. + * + * Copyright (C) 1984, Sun Microsystems, Inc. + */ + +#include <rpc/types.h> +#include <rpc/xdr.h> +#include <rpc/pmap_prot.h> + + +bool_t +xdr_pmap(xdrs, regs) +	XDR *xdrs; +	struct pmap *regs; +{ + +	if (xdr_u_long(xdrs, ®s->pm_prog) &&  +		xdr_u_long(xdrs, ®s->pm_vers) &&  +		xdr_u_long(xdrs, ®s->pm_prot)) +		return (xdr_u_long(xdrs, ®s->pm_port)); +	return (FALSE); +} diff --git a/lib/librpc/rpc/pmap_prot.h b/lib/librpc/rpc/pmap_prot.h new file mode 100644 index 000000000000..ccf7a77b4153 --- /dev/null +++ b/lib/librpc/rpc/pmap_prot.h @@ -0,0 +1,94 @@ +/* @(#)pmap_prot.h	2.1 88/07/29 4.0 RPCSRC; from 1.14 88/02/08 SMI */ +/* + * Sun RPC is a product of Sun Microsystems, Inc. and is provided for + * unrestricted use provided that this legend is included on all tape + * media and as a part of the software program in whole or part.  Users + * may copy or modify Sun RPC without charge, but are not authorized + * to license or distribute it to anyone else except as part of a product or + * program developed by the user. + *  + * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE + * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR + * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. + *  + * Sun RPC is provided with no support and without any obligation on the + * part of Sun Microsystems, Inc. to assist in its use, correction, + * modification or enhancement. + *  + * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE + * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC + * OR ANY PART THEREOF. + *  + * In no event will Sun Microsystems, Inc. be liable for any lost revenue + * or profits or other special, indirect and consequential damages, even if + * Sun has been advised of the possibility of such damages. + *  + * Sun Microsystems, Inc. + * 2550 Garcia Avenue + * Mountain View, California  94043 + */ + +/* + * pmap_prot.h + * Protocol for the local binder service, or pmap. + * + * Copyright (C) 1984, Sun Microsystems, Inc. + * + * The following procedures are supported by the protocol: + * + * PMAPPROC_NULL() returns () + * 	takes nothing, returns nothing + * + * PMAPPROC_SET(struct pmap) returns (bool_t) + * 	TRUE is success, FALSE is failure.  Registers the tuple + *	[prog, vers, prot, port]. + * + * PMAPPROC_UNSET(struct pmap) returns (bool_t) + *	TRUE is success, FALSE is failure.  Un-registers pair + *	[prog, vers].  prot and port are ignored. + * + * PMAPPROC_GETPORT(struct pmap) returns (long unsigned). + *	0 is failure.  Otherwise returns the port number where the pair + *	[prog, vers] is registered.  It may lie! + * + * PMAPPROC_DUMP() RETURNS (struct pmaplist *) + * + * PMAPPROC_CALLIT(unsigned, unsigned, unsigned, string<>) + * 	RETURNS (port, string<>); + * usage: encapsulatedresults = PMAPPROC_CALLIT(prog, vers, proc, encapsulatedargs); + * 	Calls the procedure on the local machine.  If it is not registered, + *	this procedure is quite; ie it does not return error information!!! + *	This procedure only is supported on rpc/udp and calls via + *	rpc/udp.  This routine only passes null authentication parameters. + *	This file has no interface to xdr routines for PMAPPROC_CALLIT. + * + * The service supports remote procedure calls on udp/ip or tcp/ip socket 111. + */ + +#define PMAPPORT		((u_short)111) +#define PMAPPROG		((u_long)100000) +#define PMAPVERS		((u_long)2) +#define PMAPVERS_PROTO		((u_long)2) +#define PMAPVERS_ORIG		((u_long)1) +#define PMAPPROC_NULL		((u_long)0) +#define PMAPPROC_SET		((u_long)1) +#define PMAPPROC_UNSET		((u_long)2) +#define PMAPPROC_GETPORT	((u_long)3) +#define PMAPPROC_DUMP		((u_long)4) +#define PMAPPROC_CALLIT		((u_long)5) + +struct pmap { +	long unsigned pm_prog; +	long unsigned pm_vers; +	long unsigned pm_prot; +	long unsigned pm_port; +}; + +extern bool_t xdr_pmap(); + +struct pmaplist { +	struct pmap	pml_map; +	struct pmaplist *pml_next; +}; + +extern bool_t xdr_pmaplist(); diff --git a/lib/librpc/rpc/pmap_prot2.c b/lib/librpc/rpc/pmap_prot2.c new file mode 100644 index 000000000000..e2a8214d48ad --- /dev/null +++ b/lib/librpc/rpc/pmap_prot2.c @@ -0,0 +1,116 @@ +/* @(#)pmap_prot2.c	2.1 88/07/29 4.0 RPCSRC */ +/* + * Sun RPC is a product of Sun Microsystems, Inc. and is provided for + * unrestricted use provided that this legend is included on all tape + * media and as a part of the software program in whole or part.  Users + * may copy or modify Sun RPC without charge, but are not authorized + * to license or distribute it to anyone else except as part of a product or + * program developed by the user. + *  + * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE + * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR + * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. + *  + * Sun RPC is provided with no support and without any obligation on the + * part of Sun Microsystems, Inc. to assist in its use, correction, + * modification or enhancement. + *  + * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE + * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC + * OR ANY PART THEREOF. + *  + * In no event will Sun Microsystems, Inc. be liable for any lost revenue + * or profits or other special, indirect and consequential damages, even if + * Sun has been advised of the possibility of such damages. + *  + * Sun Microsystems, Inc. + * 2550 Garcia Avenue + * Mountain View, California  94043 + */ +#if !defined(lint) && defined(SCCSIDS) +static char sccsid[] = "@(#)pmap_prot2.c 1.3 87/08/11 Copyr 1984 Sun Micro"; +#endif + +/* + * pmap_prot2.c + * Protocol for the local binder service, or pmap. + * + * Copyright (C) 1984, Sun Microsystems, Inc. + */ + +#include <rpc/types.h> +#include <rpc/xdr.h> +#include <rpc/pmap_prot.h> + + +/*  + * What is going on with linked lists? (!) + * First recall the link list declaration from pmap_prot.h: + * + * struct pmaplist { + *	struct pmap pml_map; + *	struct pmaplist *pml_map; + * }; + * + * Compare that declaration with a corresponding xdr declaration that  + * is (a) pointer-less, and (b) recursive: + * + * typedef union switch (bool_t) { + *  + *	case TRUE: struct { + *		struct pmap; + * 		pmaplist_t foo; + *	}; + * + *	case FALSE: struct {}; + * } pmaplist_t; + * + * Notice that the xdr declaration has no nxt pointer while + * the C declaration has no bool_t variable.  The bool_t can be + * interpreted as ``more data follows me''; if FALSE then nothing + * follows this bool_t; if TRUE then the bool_t is followed by + * an actual struct pmap, and then (recursively) by the  + * xdr union, pamplist_t.   + * + * This could be implemented via the xdr_union primitive, though this + * would cause a one recursive call per element in the list.  Rather than do + * that we can ``unwind'' the recursion + * into a while loop and do the union arms in-place. + * + * The head of the list is what the C programmer wishes to past around + * the net, yet is the data that the pointer points to which is interesting; + * this sounds like a job for xdr_reference! + */ +bool_t +xdr_pmaplist(xdrs, rp) +	register XDR *xdrs; +	register struct pmaplist **rp; +{ +	/* +	 * more_elements is pre-computed in case the direction is +	 * XDR_ENCODE or XDR_FREE.  more_elements is overwritten by +	 * xdr_bool when the direction is XDR_DECODE. +	 */ +	bool_t more_elements; +	register int freeing = (xdrs->x_op == XDR_FREE); +	register struct pmaplist **next; + +	while (TRUE) { +		more_elements = (bool_t)(*rp != NULL); +		if (! xdr_bool(xdrs, &more_elements)) +			return (FALSE); +		if (! more_elements) +			return (TRUE);  /* we are done */ +		/* +		 * the unfortunate side effect of non-recursion is that in +		 * the case of freeing we must remember the next object +		 * before we free the current object ... +		 */ +		if (freeing) +			next = &((*rp)->pml_next);  +		if (! xdr_reference(xdrs, (caddr_t *)rp, +		    (u_int)sizeof(struct pmaplist), xdr_pmap)) +			return (FALSE); +		rp = (freeing) ? next : &((*rp)->pml_next); +	} +} diff --git a/lib/librpc/rpc/pmap_rmt.c b/lib/librpc/rpc/pmap_rmt.c new file mode 100644 index 000000000000..8945b2fb01b8 --- /dev/null +++ b/lib/librpc/rpc/pmap_rmt.c @@ -0,0 +1,395 @@ +/* @(#)pmap_rmt.c	2.2 88/08/01 4.0 RPCSRC */ +/* + * Sun RPC is a product of Sun Microsystems, Inc. and is provided for + * unrestricted use provided that this legend is included on all tape + * media and as a part of the software program in whole or part.  Users + * may copy or modify Sun RPC without charge, but are not authorized + * to license or distribute it to anyone else except as part of a product or + * program developed by the user. + *  + * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE + * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR + * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. + *  + * Sun RPC is provided with no support and without any obligation on the + * part of Sun Microsystems, Inc. to assist in its use, correction, + * modification or enhancement. + *  + * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE + * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC + * OR ANY PART THEREOF. + *  + * In no event will Sun Microsystems, Inc. be liable for any lost revenue + * or profits or other special, indirect and consequential damages, even if + * Sun has been advised of the possibility of such damages. + *  + * Sun Microsystems, Inc. + * 2550 Garcia Avenue + * Mountain View, California  94043 + */ +#if !defined(lint) && defined(SCCSIDS) +static char sccsid[] = "@(#)pmap_rmt.c 1.21 87/08/27 Copyr 1984 Sun Micro"; +#endif + +/* + * pmap_rmt.c + * Client interface to pmap rpc service. + * remote call and broadcast service + * + * Copyright (C) 1984, Sun Microsystems, Inc. + */ + +#include <rpc/rpc.h> +#include <rpc/pmap_prot.h> +#include <rpc/pmap_clnt.h> +#include <rpc/pmap_rmt.h> +#include <sys/socket.h> +#include <stdio.h> +#include <errno.h> +#include <net/if.h> +#include <sys/ioctl.h> +#include <arpa/inet.h> +#define MAX_BROADCAST_SIZE 1400 + +extern int errno; +static struct timeval timeout = { 3, 0 }; + + +/* + * pmapper remote-call-service interface. + * This routine is used to call the pmapper remote call service + * which will look up a service program in the port maps, and then + * remotely call that routine with the given parameters.  This allows + * programs to do a lookup and call in one step. +*/ +enum clnt_stat +pmap_rmtcall(addr, prog, vers, proc, xdrargs, argsp, xdrres, resp, tout, port_ptr) +	struct sockaddr_in *addr; +	u_long prog, vers, proc; +	xdrproc_t xdrargs, xdrres; +	caddr_t argsp, resp; +	struct timeval tout; +	u_long *port_ptr; +{ +	int socket = -1; +	register CLIENT *client; +	struct rmtcallargs a; +	struct rmtcallres r; +	enum clnt_stat stat; + +	addr->sin_port = htons(PMAPPORT); +	client = clntudp_create(addr, PMAPPROG, PMAPVERS, timeout, &socket); +	if (client != (CLIENT *)NULL) { +		a.prog = prog; +		a.vers = vers; +		a.proc = proc; +		a.args_ptr = argsp; +		a.xdr_args = xdrargs; +		r.port_ptr = port_ptr; +		r.results_ptr = resp; +		r.xdr_results = xdrres; +		stat = CLNT_CALL(client, PMAPPROC_CALLIT, xdr_rmtcall_args, &a, +		    xdr_rmtcallres, &r, tout); +		CLNT_DESTROY(client); +	} else { +		stat = RPC_FAILED; +	} +	(void)close(socket); +	addr->sin_port = 0; +	return (stat); +} + + +/* + * XDR remote call arguments + * written for XDR_ENCODE direction only + */ +bool_t +xdr_rmtcall_args(xdrs, cap) +	register XDR *xdrs; +	register struct rmtcallargs *cap; +{ +	u_int lenposition, argposition, position; + +	if (xdr_u_long(xdrs, &(cap->prog)) && +	    xdr_u_long(xdrs, &(cap->vers)) && +	    xdr_u_long(xdrs, &(cap->proc))) { +		lenposition = XDR_GETPOS(xdrs); +		if (! xdr_u_long(xdrs, &(cap->arglen))) +		    return (FALSE); +		argposition = XDR_GETPOS(xdrs); +		if (! (*(cap->xdr_args))(xdrs, cap->args_ptr)) +		    return (FALSE); +		position = XDR_GETPOS(xdrs); +		cap->arglen = (u_long)position - (u_long)argposition; +		XDR_SETPOS(xdrs, lenposition); +		if (! xdr_u_long(xdrs, &(cap->arglen))) +		    return (FALSE); +		XDR_SETPOS(xdrs, position); +		return (TRUE); +	} +	return (FALSE); +} + +/* + * XDR remote call results + * written for XDR_DECODE direction only + */ +bool_t +xdr_rmtcallres(xdrs, crp) +	register XDR *xdrs; +	register struct rmtcallres *crp; +{ +	caddr_t port_ptr; + +	port_ptr = (caddr_t)crp->port_ptr; +	if (xdr_reference(xdrs, &port_ptr, sizeof (u_long), +	    xdr_u_long) && xdr_u_long(xdrs, &crp->resultslen)) { +		crp->port_ptr = (u_long *)port_ptr; +		return ((*(crp->xdr_results))(xdrs, crp->results_ptr)); +	} +	return (FALSE); +} + + +/* + * The following is kludged-up support for simple rpc broadcasts. + * Someday a large, complicated system will replace these trivial  + * routines which only support udp/ip . + */ + +static int +getbroadcastnets(addrs, sock, buf) +	struct in_addr *addrs; +	int sock;  /* any valid socket will do */ +	char *buf;  /* why allocxate more when we can use existing... */ +{ +	struct ifconf ifc; +        struct ifreq ifreq, *ifr; +	struct sockaddr_in *sin; +        char *cp, *cplim; +        int n, i = 0; + +        ifc.ifc_len = UDPMSGSIZE; +        ifc.ifc_buf = buf; +        if (ioctl(sock, SIOCGIFCONF, (char *)&ifc) < 0) { +                perror("broadcast: ioctl (get interface configuration)"); +                return (0); +        } +#define max(a, b) (a > b ? a : b) +#define size(p)	max((p).sa_len, sizeof(p)) +	cplim = buf + ifc.ifc_len; /*skip over if's with big ifr_addr's */ +	for (cp = buf; cp < cplim; +			cp += sizeof (ifr->ifr_name) + size(ifr->ifr_addr)) { +		ifr = (struct ifreq *)cp; +		if (ifr->ifr_addr.sa_family != AF_INET) +			continue; +		ifreq = *ifr; +                if (ioctl(sock, SIOCGIFFLAGS, (char *)&ifreq) < 0) { +                        perror("broadcast: ioctl (get interface flags)"); +                        continue; +                } +                if ((ifreq.ifr_flags & IFF_BROADCAST) && +		    (ifreq.ifr_flags & IFF_UP)) { +			sin = (struct sockaddr_in *)&ifr->ifr_addr; +#ifdef SIOCGIFBRDADDR   /* 4.3BSD */ +			if (ioctl(sock, SIOCGIFBRDADDR, (char *)&ifreq) < 0) { +				addrs[i++] = +				    inet_makeaddr(inet_netof(sin->sin_addr), +				    INADDR_ANY); +			} else { +				addrs[i++] = ((struct sockaddr_in*) +				  &ifreq.ifr_addr)->sin_addr; +			} +#else /* 4.2 BSD */ +			addrs[i++] = inet_makeaddr(inet_netof(sin->sin_addr), +			    INADDR_ANY); +#endif +		} +	} +	return (i); +} + +typedef bool_t (*resultproc_t)(); + +enum clnt_stat  +clnt_broadcast(prog, vers, proc, xargs, argsp, xresults, resultsp, eachresult) +	u_long		prog;		/* program number */ +	u_long		vers;		/* version number */ +	u_long		proc;		/* procedure number */ +	xdrproc_t	xargs;		/* xdr routine for args */ +	caddr_t		argsp;		/* pointer to args */ +	xdrproc_t	xresults;	/* xdr routine for results */ +	caddr_t		resultsp;	/* pointer to results */ +	resultproc_t	eachresult;	/* call with each result obtained */ +{ +	enum clnt_stat stat; +	AUTH *unix_auth = authunix_create_default(); +	XDR xdr_stream; +	register XDR *xdrs = &xdr_stream; +	int outlen, inlen, fromlen, nets; +	register int sock; +	int on = 1; +#ifdef FD_SETSIZE +	fd_set mask; +	fd_set readfds; +#else +	int readfds; +	register int mask; +#endif /* def FD_SETSIZE */ +	register int i; +	bool_t done = FALSE; +	register u_long xid; +	u_long port; +	struct in_addr addrs[20]; +	struct sockaddr_in baddr, raddr; /* broadcast and response addresses */ +	struct rmtcallargs a; +	struct rmtcallres r; +	struct rpc_msg msg; +	struct timeval t;  +	char outbuf[MAX_BROADCAST_SIZE], inbuf[UDPMSGSIZE]; + +	/* +	 * initialization: create a socket, a broadcast address, and +	 * preserialize the arguments into a send buffer. +	 */ +	if ((sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) { +		perror("Cannot create socket for broadcast rpc"); +		stat = RPC_CANTSEND; +		goto done_broad; +	} +#ifdef SO_BROADCAST +	if (setsockopt(sock, SOL_SOCKET, SO_BROADCAST, &on, sizeof (on)) < 0) { +		perror("Cannot set socket option SO_BROADCAST"); +		stat = RPC_CANTSEND; +		goto done_broad; +	} +#endif /* def SO_BROADCAST */ +#ifdef FD_SETSIZE +	FD_ZERO(&mask); +	FD_SET(sock, &mask); +#else +	mask = (1 << sock); +#endif /* def FD_SETSIZE */ +	nets = getbroadcastnets(addrs, sock, inbuf); +	bzero((char *)&baddr, sizeof (baddr)); +	baddr.sin_family = AF_INET; +	baddr.sin_port = htons(PMAPPORT); +	baddr.sin_addr.s_addr = htonl(INADDR_ANY); +/*	baddr.sin_addr.S_un.S_addr = htonl(INADDR_ANY); */ +	(void)gettimeofday(&t, (struct timezone *)0); +	msg.rm_xid = xid = getpid() ^ t.tv_sec ^ t.tv_usec; +	t.tv_usec = 0; +	msg.rm_direction = CALL; +	msg.rm_call.cb_rpcvers = RPC_MSG_VERSION; +	msg.rm_call.cb_prog = PMAPPROG; +	msg.rm_call.cb_vers = PMAPVERS; +	msg.rm_call.cb_proc = PMAPPROC_CALLIT; +	msg.rm_call.cb_cred = unix_auth->ah_cred; +	msg.rm_call.cb_verf = unix_auth->ah_verf; +	a.prog = prog; +	a.vers = vers; +	a.proc = proc; +	a.xdr_args = xargs; +	a.args_ptr = argsp; +	r.port_ptr = &port; +	r.xdr_results = xresults; +	r.results_ptr = resultsp; +	xdrmem_create(xdrs, outbuf, MAX_BROADCAST_SIZE, XDR_ENCODE); +	if ((! xdr_callmsg(xdrs, &msg)) || (! xdr_rmtcall_args(xdrs, &a))) { +		stat = RPC_CANTENCODEARGS; +		goto done_broad; +	} +	outlen = (int)xdr_getpos(xdrs); +	xdr_destroy(xdrs); +	/* +	 * Basic loop: broadcast a packet and wait a while for response(s). +	 * The response timeout grows larger per iteration. +	 */ +	for (t.tv_sec = 4; t.tv_sec <= 14; t.tv_sec += 2) { +		for (i = 0; i < nets; i++) { +			baddr.sin_addr = addrs[i]; +			if (sendto(sock, outbuf, outlen, 0, +				(struct sockaddr *)&baddr, +				sizeof (struct sockaddr)) != outlen) { +				perror("Cannot send broadcast packet"); +				stat = RPC_CANTSEND; +				goto done_broad; +			} +		} +		if (eachresult == NULL) { +			stat = RPC_SUCCESS; +			goto done_broad; +		} +	recv_again: +		msg.acpted_rply.ar_verf = _null_auth; +		msg.acpted_rply.ar_results.where = (caddr_t)&r; +                msg.acpted_rply.ar_results.proc = xdr_rmtcallres; +		readfds = mask; +		switch (select(_rpc_dtablesize(), &readfds, (int *)NULL,  +			       (int *)NULL, &t)) { + +		case 0:  /* timed out */ +			stat = RPC_TIMEDOUT; +			continue; + +		case -1:  /* some kind of error */ +			if (errno == EINTR) +				goto recv_again; +			perror("Broadcast select problem"); +			stat = RPC_CANTRECV; +			goto done_broad; + +		}  /* end of select results switch */ +	try_again: +		fromlen = sizeof(struct sockaddr); +		inlen = recvfrom(sock, inbuf, UDPMSGSIZE, 0, +			(struct sockaddr *)&raddr, &fromlen); +		if (inlen < 0) { +			if (errno == EINTR) +				goto try_again; +			perror("Cannot receive reply to broadcast"); +			stat = RPC_CANTRECV; +			goto done_broad; +		} +		if (inlen < sizeof(u_long)) +			goto recv_again; +		/* +		 * see if reply transaction id matches sent id. +		 * If so, decode the results. +		 */ +		xdrmem_create(xdrs, inbuf, (u_int)inlen, XDR_DECODE); +		if (xdr_replymsg(xdrs, &msg)) { +			if ((msg.rm_xid == xid) && +				(msg.rm_reply.rp_stat == MSG_ACCEPTED) && +				(msg.acpted_rply.ar_stat == SUCCESS)) { +				raddr.sin_port = htons((u_short)port); +				done = (*eachresult)(resultsp, &raddr); +			} +			/* otherwise, we just ignore the errors ... */ +		} else { +#ifdef notdef +			/* some kind of deserialization problem ... */ +			if (msg.rm_xid == xid) +				fprintf(stderr, "Broadcast deserialization problem"); +			/* otherwise, just random garbage */ +#endif +		} +		xdrs->x_op = XDR_FREE; +		msg.acpted_rply.ar_results.proc = xdr_void; +		(void)xdr_replymsg(xdrs, &msg); +		(void)(*xresults)(xdrs, resultsp); +		xdr_destroy(xdrs); +		if (done) { +			stat = RPC_SUCCESS; +			goto done_broad; +		} else { +			goto recv_again; +		} +	} +done_broad: +	(void)close(sock); +	AUTH_DESTROY(unix_auth); +	return (stat); +} + diff --git a/lib/librpc/rpc/pmap_rmt.h b/lib/librpc/rpc/pmap_rmt.h new file mode 100644 index 000000000000..ee68cebec221 --- /dev/null +++ b/lib/librpc/rpc/pmap_rmt.h @@ -0,0 +1,53 @@ +/* @(#)pmap_rmt.h	2.1 88/07/29 4.0 RPCSRC; from 1.2 88/02/08 SMI */ +/* + * Sun RPC is a product of Sun Microsystems, Inc. and is provided for + * unrestricted use provided that this legend is included on all tape + * media and as a part of the software program in whole or part.  Users + * may copy or modify Sun RPC without charge, but are not authorized + * to license or distribute it to anyone else except as part of a product or + * program developed by the user. + *  + * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE + * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR + * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. + *  + * Sun RPC is provided with no support and without any obligation on the + * part of Sun Microsystems, Inc. to assist in its use, correction, + * modification or enhancement. + *  + * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE + * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC + * OR ANY PART THEREOF. + *  + * In no event will Sun Microsystems, Inc. be liable for any lost revenue + * or profits or other special, indirect and consequential damages, even if + * Sun has been advised of the possibility of such damages. + *  + * Sun Microsystems, Inc. + * 2550 Garcia Avenue + * Mountain View, California  94043 + */ + +/* + * Structures and XDR routines for parameters to and replies from + * the portmapper remote-call-service. + * + * Copyright (C) 1986, Sun Microsystems, Inc. + */ + +struct rmtcallargs { +	u_long prog, vers, proc, arglen; +	caddr_t args_ptr; +	xdrproc_t xdr_args; +}; + +bool_t xdr_rmtcall_args(); + +struct rmtcallres { +	u_long *port_ptr; +	u_long resultslen; +	caddr_t results_ptr; +	xdrproc_t xdr_results; +}; + +bool_t xdr_rmtcallres(); diff --git a/lib/librpc/rpc/rpc.h b/lib/librpc/rpc/rpc.h new file mode 100644 index 000000000000..e46e1ff0f5ff --- /dev/null +++ b/lib/librpc/rpc/rpc.h @@ -0,0 +1,80 @@ +/* @(#)rpc.h	2.4 89/07/11 4.0 RPCSRC; from 1.9 88/02/08 SMI */ +/* + * Sun RPC is a product of Sun Microsystems, Inc. and is provided for + * unrestricted use provided that this legend is included on all tape + * media and as a part of the software program in whole or part.  Users + * may copy or modify Sun RPC without charge, but are not authorized + * to license or distribute it to anyone else except as part of a product or + * program developed by the user. + *  + * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE + * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR + * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. + *  + * Sun RPC is provided with no support and without any obligation on the + * part of Sun Microsystems, Inc. to assist in its use, correction, + * modification or enhancement. + * + * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE + * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC + * OR ANY PART THEREOF. + * + * In no event will Sun Microsystems, Inc. be liable for any lost revenue + * or profits or other special, indirect and consequential damages, even if + * Sun has been advised of the possibility of such damages. + * + * Sun Microsystems, Inc. + * 2550 Garcia Avenue + * Mountain View, California  94043 + */ + +/* + * rpc.h, Just includes the billions of rpc header files necessary to + * do remote procedure calling. + * + * Copyright (C) 1984, Sun Microsystems, Inc. + */ +#ifndef __RPC_HEADER__ +#define __RPC_HEADER__ + +#include <rpc/types.h>		/* some typedefs */ +#include <netinet/in.h> + +/* external data representation interfaces */ +#include <rpc/xdr.h>		/* generic (de)serializer */ + +/* Client side only authentication */ +#include <rpc/auth.h>		/* generic authenticator (client side) */ + +/* Client side (mostly) remote procedure call */ +#include <rpc/clnt.h>		/* generic rpc stuff */ + +/* semi-private protocol headers */ +#include <rpc/rpc_msg.h>	/* protocol for rpc messages */ +#include <rpc/auth_unix.h>	/* protocol for unix style cred */ +/* + *  Uncomment-out the next line if you are building the rpc library with     + *  DES Authentication (see the README file in the secure_rpc/ directory). + */ +/*#include <rpc/auth_des.h>	 * protocol for des style cred */ + +/* Server side only remote procedure callee */ +#include <rpc/svc.h>		/* service manager and multiplexer */ +#include <rpc/svc_auth.h>	/* service side authenticator */ + +/* + * COMMENT OUT THE NEXT INCLUDE (or add to the #ifndef) IF RUNNING ON + * A VERSION OF UNIX THAT USES SUN'S NFS SOURCE.  These systems will + * already have the structures defined by <rpc/netdb.h> included in <netdb.h>. + */ +/* routines for parsing /etc/rpc */ + +struct rpcent { +      char    *r_name;        /* name of server for this rpc program */ +      char    **r_aliases;    /* alias list */ +      int     r_number;       /* rpc program number */ +}; + +struct rpcent *getrpcbyname(), *getrpcbynumber(), *getrpcent(); + +#endif /* ndef __RPC_HEADER__ */ diff --git a/lib/librpc/rpc/rpc_callmsg.c b/lib/librpc/rpc/rpc_callmsg.c new file mode 100644 index 000000000000..d9d815a6fba0 --- /dev/null +++ b/lib/librpc/rpc/rpc_callmsg.c @@ -0,0 +1,190 @@ +/* @(#)rpc_callmsg.c	2.1 88/07/29 4.0 RPCSRC */ +/* + * Sun RPC is a product of Sun Microsystems, Inc. and is provided for + * unrestricted use provided that this legend is included on all tape + * media and as a part of the software program in whole or part.  Users + * may copy or modify Sun RPC without charge, but are not authorized + * to license or distribute it to anyone else except as part of a product or + * program developed by the user. + *  + * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE + * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR + * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. + *  + * Sun RPC is provided with no support and without any obligation on the + * part of Sun Microsystems, Inc. to assist in its use, correction, + * modification or enhancement. + *  + * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE + * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC + * OR ANY PART THEREOF. + *  + * In no event will Sun Microsystems, Inc. be liable for any lost revenue + * or profits or other special, indirect and consequential damages, even if + * Sun has been advised of the possibility of such damages. + *  + * Sun Microsystems, Inc. + * 2550 Garcia Avenue + * Mountain View, California  94043 + */ +#if !defined(lint) && defined(SCCSIDS) +static char sccsid[] = "@(#)rpc_callmsg.c 1.4 87/08/11 Copyr 1984 Sun Micro"; +#endif + +/* + * rpc_callmsg.c + * + * Copyright (C) 1984, Sun Microsystems, Inc. + * + */ + +#include <sys/param.h> + +#include <rpc/rpc.h> + +/* + * XDR a call message + */ +bool_t +xdr_callmsg(xdrs, cmsg) +	register XDR *xdrs; +	register struct rpc_msg *cmsg; +{ +	register long *buf; +	register struct opaque_auth *oa; + +	if (xdrs->x_op == XDR_ENCODE) { +		if (cmsg->rm_call.cb_cred.oa_length > MAX_AUTH_BYTES) { +			return (FALSE); +		} +		if (cmsg->rm_call.cb_verf.oa_length > MAX_AUTH_BYTES) { +			return (FALSE); +		} +		buf = XDR_INLINE(xdrs, 8 * BYTES_PER_XDR_UNIT +			+ RNDUP(cmsg->rm_call.cb_cred.oa_length) +			+ 2 * BYTES_PER_XDR_UNIT +			+ RNDUP(cmsg->rm_call.cb_verf.oa_length)); +		if (buf != NULL) { +			IXDR_PUT_LONG(buf, cmsg->rm_xid); +			IXDR_PUT_ENUM(buf, cmsg->rm_direction); +			if (cmsg->rm_direction != CALL) { +				return (FALSE); +			} +			IXDR_PUT_LONG(buf, cmsg->rm_call.cb_rpcvers); +			if (cmsg->rm_call.cb_rpcvers != RPC_MSG_VERSION) { +				return (FALSE); +			} +			IXDR_PUT_LONG(buf, cmsg->rm_call.cb_prog); +			IXDR_PUT_LONG(buf, cmsg->rm_call.cb_vers); +			IXDR_PUT_LONG(buf, cmsg->rm_call.cb_proc); +			oa = &cmsg->rm_call.cb_cred; +			IXDR_PUT_ENUM(buf, oa->oa_flavor); +			IXDR_PUT_LONG(buf, oa->oa_length); +			if (oa->oa_length) { +				bcopy(oa->oa_base, (caddr_t)buf, oa->oa_length); +				buf += RNDUP(oa->oa_length) / sizeof (long); +			} +			oa = &cmsg->rm_call.cb_verf; +			IXDR_PUT_ENUM(buf, oa->oa_flavor); +			IXDR_PUT_LONG(buf, oa->oa_length); +			if (oa->oa_length) { +				bcopy(oa->oa_base, (caddr_t)buf, oa->oa_length); +				/* no real need.... +				buf += RNDUP(oa->oa_length) / sizeof (long); +				*/ +			} +			return (TRUE); +		} +	} +	if (xdrs->x_op == XDR_DECODE) { +		buf = XDR_INLINE(xdrs, 8 * BYTES_PER_XDR_UNIT); +		if (buf != NULL) { +			cmsg->rm_xid = IXDR_GET_LONG(buf); +			cmsg->rm_direction = IXDR_GET_ENUM(buf, enum msg_type); +			if (cmsg->rm_direction != CALL) { +				return (FALSE); +			} +			cmsg->rm_call.cb_rpcvers = IXDR_GET_LONG(buf); +			if (cmsg->rm_call.cb_rpcvers != RPC_MSG_VERSION) { +				return (FALSE); +			} +			cmsg->rm_call.cb_prog = IXDR_GET_LONG(buf); +			cmsg->rm_call.cb_vers = IXDR_GET_LONG(buf); +			cmsg->rm_call.cb_proc = IXDR_GET_LONG(buf); +			oa = &cmsg->rm_call.cb_cred; +			oa->oa_flavor = IXDR_GET_ENUM(buf, enum_t); +			oa->oa_length = IXDR_GET_LONG(buf); +			if (oa->oa_length) { +				if (oa->oa_length > MAX_AUTH_BYTES) { +					return (FALSE); +				} +				if (oa->oa_base == NULL) { +					oa->oa_base = (caddr_t) +						mem_alloc(oa->oa_length); +				} +				buf = XDR_INLINE(xdrs, RNDUP(oa->oa_length)); +				if (buf == NULL) { +					if (xdr_opaque(xdrs, oa->oa_base, +					    oa->oa_length) == FALSE) { +						return (FALSE); +					} +				} else { +					bcopy((caddr_t)buf, oa->oa_base, +					    oa->oa_length); +					/* no real need.... +					buf += RNDUP(oa->oa_length) / +						sizeof (long); +					*/ +				} +			} +			oa = &cmsg->rm_call.cb_verf; +			buf = XDR_INLINE(xdrs, 2 * BYTES_PER_XDR_UNIT); +			if (buf == NULL) { +				if (xdr_enum(xdrs, &oa->oa_flavor) == FALSE || +				    xdr_u_int(xdrs, &oa->oa_length) == FALSE) { +					return (FALSE); +				} +			} else { +				oa->oa_flavor = IXDR_GET_ENUM(buf, enum_t); +				oa->oa_length = IXDR_GET_LONG(buf); +			} +			if (oa->oa_length) { +				if (oa->oa_length > MAX_AUTH_BYTES) { +					return (FALSE); +				} +				if (oa->oa_base == NULL) { +					oa->oa_base = (caddr_t) +						mem_alloc(oa->oa_length); +				} +				buf = XDR_INLINE(xdrs, RNDUP(oa->oa_length)); +				if (buf == NULL) { +					if (xdr_opaque(xdrs, oa->oa_base, +					    oa->oa_length) == FALSE) { +						return (FALSE); +					} +				} else { +					bcopy((caddr_t)buf, oa->oa_base, +					    oa->oa_length); +					/* no real need... +					buf += RNDUP(oa->oa_length) / +						sizeof (long); +					*/ +				} +			} +			return (TRUE); +		} +	} +	if ( +	    xdr_u_long(xdrs, &(cmsg->rm_xid)) && +	    xdr_enum(xdrs, (enum_t *)&(cmsg->rm_direction)) && +	    (cmsg->rm_direction == CALL) && +	    xdr_u_long(xdrs, &(cmsg->rm_call.cb_rpcvers)) && +	    (cmsg->rm_call.cb_rpcvers == RPC_MSG_VERSION) && +	    xdr_u_long(xdrs, &(cmsg->rm_call.cb_prog)) && +	    xdr_u_long(xdrs, &(cmsg->rm_call.cb_vers)) && +	    xdr_u_long(xdrs, &(cmsg->rm_call.cb_proc)) && +	    xdr_opaque_auth(xdrs, &(cmsg->rm_call.cb_cred)) ) +	    return (xdr_opaque_auth(xdrs, &(cmsg->rm_call.cb_verf))); +	return (FALSE); +} + diff --git a/lib/librpc/rpc/rpc_commondata.c b/lib/librpc/rpc/rpc_commondata.c new file mode 100644 index 000000000000..75cead0875b4 --- /dev/null +++ b/lib/librpc/rpc/rpc_commondata.c @@ -0,0 +1,41 @@ +/* @(#)rpc_commondata.c	2.1 88/07/29 4.0 RPCSRC */ +/* + * Sun RPC is a product of Sun Microsystems, Inc. and is provided for + * unrestricted use provided that this legend is included on all tape + * media and as a part of the software program in whole or part.  Users + * may copy or modify Sun RPC without charge, but are not authorized + * to license or distribute it to anyone else except as part of a product or + * program developed by the user. + *  + * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE + * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR + * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. + *  + * Sun RPC is provided with no support and without any obligation on the + * part of Sun Microsystems, Inc. to assist in its use, correction, + * modification or enhancement. + *  + * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE + * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC + * OR ANY PART THEREOF. + *  + * In no event will Sun Microsystems, Inc. be liable for any lost revenue + * or profits or other special, indirect and consequential damages, even if + * Sun has been advised of the possibility of such damages. + *  + * Sun Microsystems, Inc. + * 2550 Garcia Avenue + * Mountain View, California  94043 + */ +#include <rpc/rpc.h> +/* + * This file should only contain common data (global data) that is exported + * by public interfaces  + */ +struct opaque_auth _null_auth; +#ifdef FD_SETSIZE +fd_set svc_fdset; +#else +int svc_fds; +#endif /* def FD_SETSIZE */ +struct rpc_createerr rpc_createerr; diff --git a/lib/librpc/rpc/rpc_dtablesize.c b/lib/librpc/rpc/rpc_dtablesize.c new file mode 100644 index 000000000000..a8488172e4e4 --- /dev/null +++ b/lib/librpc/rpc/rpc_dtablesize.c @@ -0,0 +1,46 @@ +/* @(#)rpc_dtablesize.c	2.1 88/07/29 4.0 RPCSRC */ +/* + * Sun RPC is a product of Sun Microsystems, Inc. and is provided for + * unrestricted use provided that this legend is included on all tape + * media and as a part of the software program in whole or part.  Users + * may copy or modify Sun RPC without charge, but are not authorized + * to license or distribute it to anyone else except as part of a product or + * program developed by the user. + *  + * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE + * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR + * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. + *  + * Sun RPC is provided with no support and without any obligation on the + * part of Sun Microsystems, Inc. to assist in its use, correction, + * modification or enhancement. + *  + * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE + * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC + * OR ANY PART THEREOF. + *  + * In no event will Sun Microsystems, Inc. be liable for any lost revenue + * or profits or other special, indirect and consequential damages, even if + * Sun has been advised of the possibility of such damages. + *  + * Sun Microsystems, Inc. + * 2550 Garcia Avenue + * Mountain View, California  94043 + */ +#if !defined(lint) && defined(SCCSIDS) +static char sccsid[] = "@(#)rpc_dtablesize.c 1.2 87/08/11 Copyr 1987 Sun Micro"; +#endif + +/* + * Cache the result of getdtablesize(), so we don't have to do an + * expensive system call every time. + */ +_rpc_dtablesize() +{ +	static int size; +	 +	if (size == 0) { +		size = getdtablesize(); +	} +	return (size); +} diff --git a/lib/librpc/rpc/rpc_msg.h b/lib/librpc/rpc/rpc_msg.h new file mode 100644 index 000000000000..b78872b6a8d6 --- /dev/null +++ b/lib/librpc/rpc/rpc_msg.h @@ -0,0 +1,187 @@ +/* @(#)rpc_msg.h	2.1 88/07/29 4.0 RPCSRC */ +/* + * Sun RPC is a product of Sun Microsystems, Inc. and is provided for + * unrestricted use provided that this legend is included on all tape + * media and as a part of the software program in whole or part.  Users + * may copy or modify Sun RPC without charge, but are not authorized + * to license or distribute it to anyone else except as part of a product or + * program developed by the user. + *  + * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE + * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR + * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. + *  + * Sun RPC is provided with no support and without any obligation on the + * part of Sun Microsystems, Inc. to assist in its use, correction, + * modification or enhancement. + *  + * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE + * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC + * OR ANY PART THEREOF. + *  + * In no event will Sun Microsystems, Inc. be liable for any lost revenue + * or profits or other special, indirect and consequential damages, even if + * Sun has been advised of the possibility of such damages. + *  + * Sun Microsystems, Inc. + * 2550 Garcia Avenue + * Mountain View, California  94043 + */ +/*      @(#)rpc_msg.h 1.7 86/07/16 SMI      */ + +/* + * rpc_msg.h + * rpc message definition + * + * Copyright (C) 1984, Sun Microsystems, Inc. + */ + +#define RPC_MSG_VERSION		((u_long) 2) +#define RPC_SERVICE_PORT	((u_short) 2048) + +/* + * Bottom up definition of an rpc message. + * NOTE: call and reply use the same overall stuct but + * different parts of unions within it. + */ + +enum msg_type { +	CALL=0, +	REPLY=1 +}; + +enum reply_stat { +	MSG_ACCEPTED=0, +	MSG_DENIED=1 +}; + +enum accept_stat { +	SUCCESS=0, +	PROG_UNAVAIL=1, +	PROG_MISMATCH=2, +	PROC_UNAVAIL=3, +	GARBAGE_ARGS=4, +	SYSTEM_ERR=5 +}; + +enum reject_stat { +	RPC_MISMATCH=0, +	AUTH_ERROR=1 +}; + +/* + * Reply part of an rpc exchange + */ + +/* + * Reply to an rpc request that was accepted by the server. + * Note: there could be an error even though the request was + * accepted. + */ +struct accepted_reply { +	struct opaque_auth	ar_verf; +	enum accept_stat	ar_stat; +	union { +		struct { +			u_long	low; +			u_long	high; +		} AR_versions; +		struct { +			caddr_t	where; +			xdrproc_t proc; +		} AR_results; +		/* and many other null cases */ +	} ru; +#define	ar_results	ru.AR_results +#define	ar_vers		ru.AR_versions +}; + +/* + * Reply to an rpc request that was rejected by the server. + */ +struct rejected_reply { +	enum reject_stat rj_stat; +	union { +		struct { +			u_long low; +			u_long high; +		} RJ_versions; +		enum auth_stat RJ_why;  /* why authentication did not work */ +	} ru; +#define	rj_vers	ru.RJ_versions +#define	rj_why	ru.RJ_why +}; + +/* + * Body of a reply to an rpc request. + */ +struct reply_body { +	enum reply_stat rp_stat; +	union { +		struct accepted_reply RP_ar; +		struct rejected_reply RP_dr; +	} ru; +#define	rp_acpt	ru.RP_ar +#define	rp_rjct	ru.RP_dr +}; + +/* + * Body of an rpc request call. + */ +struct call_body { +	u_long cb_rpcvers;	/* must be equal to two */ +	u_long cb_prog; +	u_long cb_vers; +	u_long cb_proc; +	struct opaque_auth cb_cred; +	struct opaque_auth cb_verf; /* protocol specific - provided by client */ +}; + +/* + * The rpc message + */ +struct rpc_msg { +	u_long			rm_xid; +	enum msg_type		rm_direction; +	union { +		struct call_body RM_cmb; +		struct reply_body RM_rmb; +	} ru; +#define	rm_call		ru.RM_cmb +#define	rm_reply	ru.RM_rmb +}; +#define	acpted_rply	ru.RM_rmb.ru.RP_ar +#define	rjcted_rply	ru.RM_rmb.ru.RP_dr + + +/* + * XDR routine to handle a rpc message. + * xdr_callmsg(xdrs, cmsg) + * 	XDR *xdrs; + * 	struct rpc_msg *cmsg; + */ +extern bool_t	xdr_callmsg(); + +/* + * XDR routine to pre-serialize the static part of a rpc message. + * xdr_callhdr(xdrs, cmsg) + * 	XDR *xdrs; + * 	struct rpc_msg *cmsg; + */ +extern bool_t	xdr_callhdr(); + +/* + * XDR routine to handle a rpc reply. + * xdr_replymsg(xdrs, rmsg) + * 	XDR *xdrs; + * 	struct rpc_msg *rmsg; + */ +extern bool_t	xdr_replymsg(); + +/* + * Fills in the error part of a reply message. + * _seterr_reply(msg, error) + * 	struct rpc_msg *msg; + * 	struct rpc_err *error; + */ +extern void	_seterr_reply(); diff --git a/lib/librpc/rpc/rpc_prot.c b/lib/librpc/rpc/rpc_prot.c new file mode 100644 index 000000000000..4b1319ad560f --- /dev/null +++ b/lib/librpc/rpc/rpc_prot.c @@ -0,0 +1,289 @@ +/* @(#)rpc_prot.c	2.3 88/08/07 4.0 RPCSRC */ +/* + * Sun RPC is a product of Sun Microsystems, Inc. and is provided for + * unrestricted use provided that this legend is included on all tape + * media and as a part of the software program in whole or part.  Users + * may copy or modify Sun RPC without charge, but are not authorized + * to license or distribute it to anyone else except as part of a product or + * program developed by the user. + *  + * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE + * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR + * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. + *  + * Sun RPC is provided with no support and without any obligation on the + * part of Sun Microsystems, Inc. to assist in its use, correction, + * modification or enhancement. + *  + * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE + * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC + * OR ANY PART THEREOF. + *  + * In no event will Sun Microsystems, Inc. be liable for any lost revenue + * or profits or other special, indirect and consequential damages, even if + * Sun has been advised of the possibility of such damages. + *  + * Sun Microsystems, Inc. + * 2550 Garcia Avenue + * Mountain View, California  94043 + */ +#if !defined(lint) && defined(SCCSIDS) +static char sccsid[] = "@(#)rpc_prot.c 1.36 87/08/11 Copyr 1984 Sun Micro"; +#endif + +/* + * rpc_prot.c + * + * Copyright (C) 1984, Sun Microsystems, Inc. + * + * This set of routines implements the rpc message definition, + * its serializer and some common rpc utility routines. + * The routines are meant for various implementations of rpc - + * they are NOT for the rpc client or rpc service implementations! + * Because authentication stuff is easy and is part of rpc, the opaque + * routines are also in this program. + */ + +#include <sys/param.h> + +#include <rpc/rpc.h> + +/* * * * * * * * * * * * * * XDR Authentication * * * * * * * * * * * */ + +struct opaque_auth _null_auth; + +/* + * XDR an opaque authentication struct + * (see auth.h) + */ +bool_t +xdr_opaque_auth(xdrs, ap) +	register XDR *xdrs; +	register struct opaque_auth *ap; +{ + +	if (xdr_enum(xdrs, &(ap->oa_flavor))) +		return (xdr_bytes(xdrs, &ap->oa_base, +			&ap->oa_length, MAX_AUTH_BYTES)); +	return (FALSE); +} + +/* + * XDR a DES block + */ +bool_t +xdr_des_block(xdrs, blkp) +	register XDR *xdrs; +	register des_block *blkp; +{ +	return (xdr_opaque(xdrs, (caddr_t)blkp, sizeof(des_block))); +} + +/* * * * * * * * * * * * * * XDR RPC MESSAGE * * * * * * * * * * * * * * * */ + +/* + * XDR the MSG_ACCEPTED part of a reply message union + */ +bool_t  +xdr_accepted_reply(xdrs, ar) +	register XDR *xdrs;    +	register struct accepted_reply *ar; +{ + +	/* personalized union, rather than calling xdr_union */ +	if (! xdr_opaque_auth(xdrs, &(ar->ar_verf))) +		return (FALSE); +	if (! xdr_enum(xdrs, (enum_t *)&(ar->ar_stat))) +		return (FALSE); +	switch (ar->ar_stat) { + +	case SUCCESS: +		return ((*(ar->ar_results.proc))(xdrs, ar->ar_results.where)); + +	case PROG_MISMATCH: +		if (! xdr_u_long(xdrs, &(ar->ar_vers.low))) +			return (FALSE); +		return (xdr_u_long(xdrs, &(ar->ar_vers.high))); +	} +	return (TRUE);  /* TRUE => open ended set of problems */ +} + +/* + * XDR the MSG_DENIED part of a reply message union + */ +bool_t  +xdr_rejected_reply(xdrs, rr) +	register XDR *xdrs; +	register struct rejected_reply *rr; +{ + +	/* personalized union, rather than calling xdr_union */ +	if (! xdr_enum(xdrs, (enum_t *)&(rr->rj_stat))) +		return (FALSE); +	switch (rr->rj_stat) { + +	case RPC_MISMATCH: +		if (! xdr_u_long(xdrs, &(rr->rj_vers.low))) +			return (FALSE); +		return (xdr_u_long(xdrs, &(rr->rj_vers.high))); + +	case AUTH_ERROR: +		return (xdr_enum(xdrs, (enum_t *)&(rr->rj_why))); +	} +	return (FALSE); +} + +static struct xdr_discrim reply_dscrm[3] = { +	{ (int)MSG_ACCEPTED, xdr_accepted_reply }, +	{ (int)MSG_DENIED, xdr_rejected_reply }, +	{ __dontcare__, NULL_xdrproc_t } }; + +/* + * XDR a reply message + */ +bool_t +xdr_replymsg(xdrs, rmsg) +	register XDR *xdrs; +	register struct rpc_msg *rmsg; +{ +	if ( +	    xdr_u_long(xdrs, &(rmsg->rm_xid)) &&  +	    xdr_enum(xdrs, (enum_t *)&(rmsg->rm_direction)) && +	    (rmsg->rm_direction == REPLY) ) +		return (xdr_union(xdrs, (enum_t *)&(rmsg->rm_reply.rp_stat), +		   (caddr_t)&(rmsg->rm_reply.ru), reply_dscrm, NULL_xdrproc_t)); +	return (FALSE); +} + + +/* + * Serializes the "static part" of a call message header. + * The fields include: rm_xid, rm_direction, rpcvers, prog, and vers. + * The rm_xid is not really static, but the user can easily munge on the fly. + */ +bool_t +xdr_callhdr(xdrs, cmsg) +	register XDR *xdrs; +	register struct rpc_msg *cmsg; +{ + +	cmsg->rm_direction = CALL; +	cmsg->rm_call.cb_rpcvers = RPC_MSG_VERSION; +	if ( +	    (xdrs->x_op == XDR_ENCODE) && +	    xdr_u_long(xdrs, &(cmsg->rm_xid)) && +	    xdr_enum(xdrs, (enum_t *)&(cmsg->rm_direction)) && +	    xdr_u_long(xdrs, &(cmsg->rm_call.cb_rpcvers)) && +	    xdr_u_long(xdrs, &(cmsg->rm_call.cb_prog)) ) +	    return (xdr_u_long(xdrs, &(cmsg->rm_call.cb_vers))); +	return (FALSE); +} + +/* ************************** Client utility routine ************* */ + +static void +accepted(acpt_stat, error) +	register enum accept_stat acpt_stat; +	register struct rpc_err *error; +{ + +	switch (acpt_stat) { + +	case PROG_UNAVAIL: +		error->re_status = RPC_PROGUNAVAIL; +		return; + +	case PROG_MISMATCH: +		error->re_status = RPC_PROGVERSMISMATCH; +		return; + +	case PROC_UNAVAIL: +		error->re_status = RPC_PROCUNAVAIL; +		return; + +	case GARBAGE_ARGS: +		error->re_status = RPC_CANTDECODEARGS; +		return; + +	case SYSTEM_ERR: +		error->re_status = RPC_SYSTEMERROR; +		return; + +	case SUCCESS: +		error->re_status = RPC_SUCCESS; +		return; +	} +	/* something's wrong, but we don't know what ... */ +	error->re_status = RPC_FAILED; +	error->re_lb.s1 = (long)MSG_ACCEPTED; +	error->re_lb.s2 = (long)acpt_stat; +} + +static void  +rejected(rjct_stat, error) +	register enum reject_stat rjct_stat; +	register struct rpc_err *error; +{ + +	switch (rjct_stat) { + +	case RPC_VERSMISMATCH: +		error->re_status = RPC_VERSMISMATCH; +		return; + +	case AUTH_ERROR: +		error->re_status = RPC_AUTHERROR; +		return; +	} +	/* something's wrong, but we don't know what ... */ +	error->re_status = RPC_FAILED; +	error->re_lb.s1 = (long)MSG_DENIED; +	error->re_lb.s2 = (long)rjct_stat; +} + +/* + * given a reply message, fills in the error + */ +void +_seterr_reply(msg, error) +	register struct rpc_msg *msg; +	register struct rpc_err *error; +{ + +	/* optimized for normal, SUCCESSful case */ +	switch (msg->rm_reply.rp_stat) { + +	case MSG_ACCEPTED: +		if (msg->acpted_rply.ar_stat == SUCCESS) { +			error->re_status = RPC_SUCCESS; +			return; +		}; +		accepted(msg->acpted_rply.ar_stat, error); +		break; + +	case MSG_DENIED: +		rejected(msg->rjcted_rply.rj_stat, error); +		break; + +	default: +		error->re_status = RPC_FAILED; +		error->re_lb.s1 = (long)(msg->rm_reply.rp_stat); +		break; +	} +	switch (error->re_status) { + +	case RPC_VERSMISMATCH: +		error->re_vers.low = msg->rjcted_rply.rj_vers.low; +		error->re_vers.high = msg->rjcted_rply.rj_vers.high; +		break; + +	case RPC_AUTHERROR: +		error->re_why = msg->rjcted_rply.rj_why; +		break; + +	case RPC_PROGVERSMISMATCH: +		error->re_vers.low = msg->acpted_rply.ar_vers.low; +		error->re_vers.high = msg->acpted_rply.ar_vers.high; +		break; +	} +} diff --git a/lib/librpc/rpc/svc.c b/lib/librpc/rpc/svc.c new file mode 100644 index 000000000000..3327ee5bdd6c --- /dev/null +++ b/lib/librpc/rpc/svc.c @@ -0,0 +1,479 @@ +/* @(#)svc.c	2.4 88/08/11 4.0 RPCSRC; from 1.44 88/02/08 SMI */ +/* + * Sun RPC is a product of Sun Microsystems, Inc. and is provided for + * unrestricted use provided that this legend is included on all tape + * media and as a part of the software program in whole or part.  Users + * may copy or modify Sun RPC without charge, but are not authorized + * to license or distribute it to anyone else except as part of a product or + * program developed by the user. + *  + * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE + * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR + * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. + *  + * Sun RPC is provided with no support and without any obligation on the + * part of Sun Microsystems, Inc. to assist in its use, correction, + * modification or enhancement. + *  + * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE + * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC + * OR ANY PART THEREOF. + *  + * In no event will Sun Microsystems, Inc. be liable for any lost revenue + * or profits or other special, indirect and consequential damages, even if + * Sun has been advised of the possibility of such damages. + *  + * Sun Microsystems, Inc. + * 2550 Garcia Avenue + * Mountain View, California  94043 + */ +#if !defined(lint) && defined(SCCSIDS) +static char sccsid[] = "@(#)svc.c 1.41 87/10/13 Copyr 1984 Sun Micro"; +#endif + +/* + * svc.c, Server-side remote procedure call interface. + * + * There are two sets of procedures here.  The xprt routines are + * for handling transport handles.  The svc routines handle the + * list of service routines. + * + * Copyright (C) 1984, Sun Microsystems, Inc. + */ + +#include <sys/errno.h> +#include <rpc/rpc.h> +#include <rpc/pmap_clnt.h> + +extern int errno; + +#ifdef FD_SETSIZE +static SVCXPRT **xports; +#else +#define NOFILE 32 + +static SVCXPRT *xports[NOFILE]; +#endif /* def FD_SETSIZE */ + +#define NULL_SVC ((struct svc_callout *)0) +#define	RQCRED_SIZE	400		/* this size is excessive */ + +/* + * The services list + * Each entry represents a set of procedures (an rpc program). + * The dispatch routine takes request structs and runs the + * apropriate procedure. + */ +static struct svc_callout { +	struct svc_callout *sc_next; +	u_long		    sc_prog; +	u_long		    sc_vers; +	void		    (*sc_dispatch)(); +} *svc_head; + +static struct svc_callout *svc_find(); + +/* ***************  SVCXPRT related stuff **************** */ + +/* + * Activate a transport handle. + */ +void +xprt_register(xprt) +	SVCXPRT *xprt; +{ +	register int sock = xprt->xp_sock; + +#ifdef FD_SETSIZE +	if (xports == NULL) { +		xports = (SVCXPRT **) +			mem_alloc(FD_SETSIZE * sizeof(SVCXPRT *)); +	} +	if (sock < _rpc_dtablesize()) { +		xports[sock] = xprt; +		FD_SET(sock, &svc_fdset); +	} +#else +	if (sock < NOFILE) { +		xports[sock] = xprt; +		svc_fds |= (1 << sock); +	} +#endif /* def FD_SETSIZE */ + +} + +/* + * De-activate a transport handle.  + */ +void +xprt_unregister(xprt)  +	SVCXPRT *xprt; +{  +	register int sock = xprt->xp_sock; + +#ifdef FD_SETSIZE +	if ((sock < _rpc_dtablesize()) && (xports[sock] == xprt)) { +		xports[sock] = (SVCXPRT *)0; +		FD_CLR(sock, &svc_fdset); +	} +#else +	if ((sock < NOFILE) && (xports[sock] == xprt)) { +		xports[sock] = (SVCXPRT *)0; +		svc_fds &= ~(1 << sock); +	} +#endif /* def FD_SETSIZE */ +} + + +/* ********************** CALLOUT list related stuff ************* */ + +/* + * Add a service program to the callout list. + * The dispatch routine will be called when a rpc request for this + * program number comes in. + */ +bool_t +svc_register(xprt, prog, vers, dispatch, protocol) +	SVCXPRT *xprt; +	u_long prog; +	u_long vers; +	void (*dispatch)(); +	int protocol; +{ +	struct svc_callout *prev; +	register struct svc_callout *s; + +	if ((s = svc_find(prog, vers, &prev)) != NULL_SVC) { +		if (s->sc_dispatch == dispatch) +			goto pmap_it;  /* he is registering another xptr */ +		return (FALSE); +	} +	s = (struct svc_callout *)mem_alloc(sizeof(struct svc_callout)); +	if (s == (struct svc_callout *)0) { +		return (FALSE); +	} +	s->sc_prog = prog; +	s->sc_vers = vers; +	s->sc_dispatch = dispatch; +	s->sc_next = svc_head; +	svc_head = s; +pmap_it: +	/* now register the information with the local binder service */ +	if (protocol) { +		return (pmap_set(prog, vers, protocol, xprt->xp_port)); +	} +	return (TRUE); +} + +/* + * Remove a service program from the callout list. + */ +void +svc_unregister(prog, vers) +	u_long prog; +	u_long vers; +{ +	struct svc_callout *prev; +	register struct svc_callout *s; + +	if ((s = svc_find(prog, vers, &prev)) == NULL_SVC) +		return; +	if (prev == NULL_SVC) { +		svc_head = s->sc_next; +	} else { +		prev->sc_next = s->sc_next; +	} +	s->sc_next = NULL_SVC; +	mem_free((char *) s, (u_int) sizeof(struct svc_callout)); +	/* now unregister the information with the local binder service */ +	(void)pmap_unset(prog, vers); +} + +/* + * Search the callout list for a program number, return the callout + * struct. + */ +static struct svc_callout * +svc_find(prog, vers, prev) +	u_long prog; +	u_long vers; +	struct svc_callout **prev; +{ +	register struct svc_callout *s, *p; + +	p = NULL_SVC; +	for (s = svc_head; s != NULL_SVC; s = s->sc_next) { +		if ((s->sc_prog == prog) && (s->sc_vers == vers)) +			goto done; +		p = s; +	} +done: +	*prev = p; +	return (s); +} + +/* ******************* REPLY GENERATION ROUTINES  ************ */ + +/* + * Send a reply to an rpc request + */ +bool_t +svc_sendreply(xprt, xdr_results, xdr_location) +	register SVCXPRT *xprt; +	xdrproc_t xdr_results; +	caddr_t xdr_location; +{ +	struct rpc_msg rply;  + +	rply.rm_direction = REPLY;   +	rply.rm_reply.rp_stat = MSG_ACCEPTED;  +	rply.acpted_rply.ar_verf = xprt->xp_verf;  +	rply.acpted_rply.ar_stat = SUCCESS; +	rply.acpted_rply.ar_results.where = xdr_location; +	rply.acpted_rply.ar_results.proc = xdr_results; +	return (SVC_REPLY(xprt, &rply));  +} + +/* + * No procedure error reply + */ +void +svcerr_noproc(xprt) +	register SVCXPRT *xprt; +{ +	struct rpc_msg rply; + +	rply.rm_direction = REPLY; +	rply.rm_reply.rp_stat = MSG_ACCEPTED; +	rply.acpted_rply.ar_verf = xprt->xp_verf; +	rply.acpted_rply.ar_stat = PROC_UNAVAIL; +	SVC_REPLY(xprt, &rply); +} + +/* + * Can't decode args error reply + */ +void +svcerr_decode(xprt) +	register SVCXPRT *xprt; +{ +	struct rpc_msg rply;  + +	rply.rm_direction = REPLY;  +	rply.rm_reply.rp_stat = MSG_ACCEPTED;  +	rply.acpted_rply.ar_verf = xprt->xp_verf; +	rply.acpted_rply.ar_stat = GARBAGE_ARGS; +	SVC_REPLY(xprt, &rply);  +} + +/* + * Some system error + */ +void +svcerr_systemerr(xprt) +	register SVCXPRT *xprt; +{ +	struct rpc_msg rply;  + +	rply.rm_direction = REPLY;  +	rply.rm_reply.rp_stat = MSG_ACCEPTED;  +	rply.acpted_rply.ar_verf = xprt->xp_verf; +	rply.acpted_rply.ar_stat = SYSTEM_ERR; +	SVC_REPLY(xprt, &rply);  +} + +/* + * Authentication error reply + */ +void +svcerr_auth(xprt, why) +	SVCXPRT *xprt; +	enum auth_stat why; +{ +	struct rpc_msg rply; + +	rply.rm_direction = REPLY; +	rply.rm_reply.rp_stat = MSG_DENIED; +	rply.rjcted_rply.rj_stat = AUTH_ERROR; +	rply.rjcted_rply.rj_why = why; +	SVC_REPLY(xprt, &rply); +} + +/* + * Auth too weak error reply + */ +void +svcerr_weakauth(xprt) +	SVCXPRT *xprt; +{ + +	svcerr_auth(xprt, AUTH_TOOWEAK); +} + +/* + * Program unavailable error reply + */ +void  +svcerr_noprog(xprt) +	register SVCXPRT *xprt; +{ +	struct rpc_msg rply;   + +	rply.rm_direction = REPLY;    +	rply.rm_reply.rp_stat = MSG_ACCEPTED;   +	rply.acpted_rply.ar_verf = xprt->xp_verf;   +	rply.acpted_rply.ar_stat = PROG_UNAVAIL; +	SVC_REPLY(xprt, &rply); +} + +/* + * Program version mismatch error reply + */ +void   +svcerr_progvers(xprt, low_vers, high_vers) +	register SVCXPRT *xprt;  +	u_long low_vers; +	u_long high_vers; +{ +	struct rpc_msg rply; + +	rply.rm_direction = REPLY; +	rply.rm_reply.rp_stat = MSG_ACCEPTED; +	rply.acpted_rply.ar_verf = xprt->xp_verf; +	rply.acpted_rply.ar_stat = PROG_MISMATCH; +	rply.acpted_rply.ar_vers.low = low_vers; +	rply.acpted_rply.ar_vers.high = high_vers; +	SVC_REPLY(xprt, &rply); +} + +/* ******************* SERVER INPUT STUFF ******************* */ + +/* + * Get server side input from some transport. + * + * Statement of authentication parameters management: + * This function owns and manages all authentication parameters, specifically + * the "raw" parameters (msg.rm_call.cb_cred and msg.rm_call.cb_verf) and + * the "cooked" credentials (rqst->rq_clntcred). + * However, this function does not know the structure of the cooked + * credentials, so it make the following assumptions:  + *   a) the structure is contiguous (no pointers), and + *   b) the cred structure size does not exceed RQCRED_SIZE bytes.  + * In all events, all three parameters are freed upon exit from this routine. + * The storage is trivially management on the call stack in user land, but + * is mallocated in kernel land. + */ + +void +svc_getreq(rdfds) +	int rdfds; +{ +#ifdef FD_SETSIZE +	fd_set readfds; + +	FD_ZERO(&readfds); +	readfds.fds_bits[0] = rdfds; +	svc_getreqset(&readfds); +#else +	int readfds = rdfds & svc_fds; + +	svc_getreqset(&readfds); +#endif /* def FD_SETSIZE */ +} + +void +svc_getreqset(readfds) +#ifdef FD_SETSIZE +	fd_set *readfds; +{ +#else +	int *readfds; +{ +    int readfds_local = *readfds; +#endif /* def FD_SETSIZE */ +	enum xprt_stat stat; +	struct rpc_msg msg; +	int prog_found; +	u_long low_vers; +	u_long high_vers; +	struct svc_req r; +	register SVCXPRT *xprt; +	register u_long mask; +	register int bit; +	register u_long *maskp; +	register int setsize; +	register int sock; +	char cred_area[2*MAX_AUTH_BYTES + RQCRED_SIZE]; +	msg.rm_call.cb_cred.oa_base = cred_area; +	msg.rm_call.cb_verf.oa_base = &(cred_area[MAX_AUTH_BYTES]); +	r.rq_clntcred = &(cred_area[2*MAX_AUTH_BYTES]); + + +#ifdef FD_SETSIZE +	setsize = _rpc_dtablesize();	 +	maskp = (u_long *)readfds->fds_bits; +	for (sock = 0; sock < setsize; sock += NFDBITS) { +	    for (mask = *maskp++; bit = ffs(mask); mask ^= (1 << (bit - 1))) { +		/* sock has input waiting */ +		xprt = xports[sock + bit - 1]; +#else +	for (sock = 0; readfds_local != 0; sock++, readfds_local >>= 1) { +	    if ((readfds_local & 1) != 0) { +		/* sock has input waiting */ +		xprt = xports[sock]; +#endif /* def FD_SETSIZE */ +		/* now receive msgs from xprtprt (support batch calls) */ +		do { +			if (SVC_RECV(xprt, &msg)) { + +				/* now find the exported program and call it */ +				register struct svc_callout *s; +				enum auth_stat why; + +				r.rq_xprt = xprt; +				r.rq_prog = msg.rm_call.cb_prog; +				r.rq_vers = msg.rm_call.cb_vers; +				r.rq_proc = msg.rm_call.cb_proc; +				r.rq_cred = msg.rm_call.cb_cred; +				/* first authenticate the message */ +				if ((why= _authenticate(&r, &msg)) != AUTH_OK) { +					svcerr_auth(xprt, why); +					goto call_done; +				} +				/* now match message with a registered service*/ +				prog_found = FALSE; +				low_vers = 0 - 1; +				high_vers = 0; +				for (s = svc_head; s != NULL_SVC; s = s->sc_next) { +					if (s->sc_prog == r.rq_prog) { +						if (s->sc_vers == r.rq_vers) { +							(*s->sc_dispatch)(&r, xprt); +							goto call_done; +						}  /* found correct version */ +						prog_found = TRUE; +						if (s->sc_vers < low_vers) +							low_vers = s->sc_vers; +						if (s->sc_vers > high_vers) +							high_vers = s->sc_vers; +					}   /* found correct program */ +				} +				/* +				 * if we got here, the program or version +				 * is not served ... +				 */ +				if (prog_found) +					svcerr_progvers(xprt, +					low_vers, high_vers); +				else +					 svcerr_noprog(xprt); +				/* Fall through to ... */ +			} +		call_done: +			if ((stat = SVC_STAT(xprt)) == XPRT_DIED){ +				SVC_DESTROY(xprt); +				break; +			} +		} while (stat == XPRT_MOREREQS); +	    } +	} +} diff --git a/lib/librpc/rpc/svc.h b/lib/librpc/rpc/svc.h new file mode 100644 index 000000000000..dbae45df68b3 --- /dev/null +++ b/lib/librpc/rpc/svc.h @@ -0,0 +1,280 @@ +/* @(#)svc.h	2.2 88/07/29 4.0 RPCSRC; from 1.20 88/02/08 SMI */ +/* + * Sun RPC is a product of Sun Microsystems, Inc. and is provided for + * unrestricted use provided that this legend is included on all tape + * media and as a part of the software program in whole or part.  Users + * may copy or modify Sun RPC without charge, but are not authorized + * to license or distribute it to anyone else except as part of a product or + * program developed by the user. + *  + * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE + * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR + * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. + *  + * Sun RPC is provided with no support and without any obligation on the + * part of Sun Microsystems, Inc. to assist in its use, correction, + * modification or enhancement. + *  + * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE + * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC + * OR ANY PART THEREOF. + *  + * In no event will Sun Microsystems, Inc. be liable for any lost revenue + * or profits or other special, indirect and consequential damages, even if + * Sun has been advised of the possibility of such damages. + *  + * Sun Microsystems, Inc. + * 2550 Garcia Avenue + * Mountain View, California  94043 + */ + +/* + * svc.h, Server-side remote procedure call interface. + * + * Copyright (C) 1984, Sun Microsystems, Inc. + */ + +#ifndef __SVC_HEADER__ +#define __SVC_HEADER__ + +/* + * This interface must manage two items concerning remote procedure calling: + * + * 1) An arbitrary number of transport connections upon which rpc requests + * are received.  The two most notable transports are TCP and UDP;  they are + * created and registered by routines in svc_tcp.c and svc_udp.c, respectively; + * they in turn call xprt_register and xprt_unregister. + * + * 2) An arbitrary number of locally registered services.  Services are + * described by the following four data: program number, version number, + * "service dispatch" function, a transport handle, and a boolean that + * indicates whether or not the exported program should be registered with a + * local binder service;  if true the program's number and version and the + * port number from the transport handle are registered with the binder. + * These data are registered with the rpc svc system via svc_register. + * + * A service's dispatch function is called whenever an rpc request comes in + * on a transport.  The request's program and version numbers must match + * those of the registered service.  The dispatch function is passed two + * parameters, struct svc_req * and SVCXPRT *, defined below. + */ + +enum xprt_stat { +	XPRT_DIED, +	XPRT_MOREREQS, +	XPRT_IDLE +}; + +/* + * Server side transport handle + */ +typedef struct { +	int		xp_sock; +	u_short		xp_port;	 /* associated port number */ +	struct xp_ops { +	    bool_t	(*xp_recv)();	 /* receive incomming requests */ +	    enum xprt_stat (*xp_stat)(); /* get transport status */ +	    bool_t	(*xp_getargs)(); /* get arguments */ +	    bool_t	(*xp_reply)();	 /* send reply */ +	    bool_t	(*xp_freeargs)();/* free mem allocated for args */ +	    void	(*xp_destroy)(); /* destroy this struct */ +	} *xp_ops; +	int		xp_addrlen;	 /* length of remote address */ +	struct sockaddr_in xp_raddr;	 /* remote address */ +	struct opaque_auth xp_verf;	 /* raw response verifier */ +	caddr_t		xp_p1;		 /* private */ +	caddr_t		xp_p2;		 /* private */ +} SVCXPRT; + +/* + *  Approved way of getting address of caller + */ +#define svc_getcaller(x) (&(x)->xp_raddr) + +/* + * Operations defined on an SVCXPRT handle + * + * SVCXPRT		*xprt; + * struct rpc_msg	*msg; + * xdrproc_t		 xargs; + * caddr_t		 argsp; + */ +#define SVC_RECV(xprt, msg)				\ +	(*(xprt)->xp_ops->xp_recv)((xprt), (msg)) +#define svc_recv(xprt, msg)				\ +	(*(xprt)->xp_ops->xp_recv)((xprt), (msg)) + +#define SVC_STAT(xprt)					\ +	(*(xprt)->xp_ops->xp_stat)(xprt) +#define svc_stat(xprt)					\ +	(*(xprt)->xp_ops->xp_stat)(xprt) + +#define SVC_GETARGS(xprt, xargs, argsp)			\ +	(*(xprt)->xp_ops->xp_getargs)((xprt), (xargs), (argsp)) +#define svc_getargs(xprt, xargs, argsp)			\ +	(*(xprt)->xp_ops->xp_getargs)((xprt), (xargs), (argsp)) + +#define SVC_REPLY(xprt, msg)				\ +	(*(xprt)->xp_ops->xp_reply) ((xprt), (msg)) +#define svc_reply(xprt, msg)				\ +	(*(xprt)->xp_ops->xp_reply) ((xprt), (msg)) + +#define SVC_FREEARGS(xprt, xargs, argsp)		\ +	(*(xprt)->xp_ops->xp_freeargs)((xprt), (xargs), (argsp)) +#define svc_freeargs(xprt, xargs, argsp)		\ +	(*(xprt)->xp_ops->xp_freeargs)((xprt), (xargs), (argsp)) + +#define SVC_DESTROY(xprt)				\ +	(*(xprt)->xp_ops->xp_destroy)(xprt) +#define svc_destroy(xprt)				\ +	(*(xprt)->xp_ops->xp_destroy)(xprt) + + +/* + * Service request + */ +struct svc_req { +	u_long		rq_prog;	/* service program number */ +	u_long		rq_vers;	/* service protocol version */ +	u_long		rq_proc;	/* the desired procedure */ +	struct opaque_auth rq_cred;	/* raw creds from the wire */ +	caddr_t		rq_clntcred;	/* read only cooked cred */ +	SVCXPRT	*rq_xprt;		/* associated transport */ +}; + + +/* + * Service registration + * + * svc_register(xprt, prog, vers, dispatch, protocol) + *	SVCXPRT *xprt; + *	u_long prog; + *	u_long vers; + *	void (*dispatch)(); + *	int protocol;  (like TCP or UDP, zero means do not register) + */ +extern bool_t	svc_register(); + +/* + * Service un-registration + * + * svc_unregister(prog, vers) + *	u_long prog; + *	u_long vers; + */ +extern void	svc_unregister(); + +/* + * Transport registration. + * + * xprt_register(xprt) + *	SVCXPRT *xprt; + */ +extern void	xprt_register(); + +/* + * Transport un-register + * + * xprt_unregister(xprt) + *	SVCXPRT *xprt; + */ +extern void	xprt_unregister(); + + + + +/* + * When the service routine is called, it must first check to see if it + * knows about the procedure;  if not, it should call svcerr_noproc + * and return.  If so, it should deserialize its arguments via  + * SVC_GETARGS (defined above).  If the deserialization does not work, + * svcerr_decode should be called followed by a return.  Successful + * decoding of the arguments should be followed the execution of the + * procedure's code and a call to svc_sendreply. + * + * Also, if the service refuses to execute the procedure due to too- + * weak authentication parameters, svcerr_weakauth should be called. + * Note: do not confuse access-control failure with weak authentication! + * + * NB: In pure implementations of rpc, the caller always waits for a reply + * msg.  This message is sent when svc_sendreply is called.   + * Therefore pure service implementations should always call + * svc_sendreply even if the function logically returns void;  use + * xdr.h - xdr_void for the xdr routine.  HOWEVER, tcp based rpc allows + * for the abuse of pure rpc via batched calling or pipelining.  In the + * case of a batched call, svc_sendreply should NOT be called since + * this would send a return message, which is what batching tries to avoid. + * It is the service/protocol writer's responsibility to know which calls are + * batched and which are not.  Warning: responding to batch calls may + * deadlock the caller and server processes! + */ + +extern bool_t	svc_sendreply(); +extern void	svcerr_decode(); +extern void	svcerr_weakauth(); +extern void	svcerr_noproc(); +extern void	svcerr_progvers(); +extern void	svcerr_auth(); +extern void	svcerr_noprog(); +extern void	svcerr_systemerr(); +     +/* + * Lowest level dispatching -OR- who owns this process anyway. + * Somebody has to wait for incoming requests and then call the correct + * service routine.  The routine svc_run does infinite waiting; i.e., + * svc_run never returns. + * Since another (co-existant) package may wish to selectively wait for + * incoming calls or other events outside of the rpc architecture, the + * routine svc_getreq is provided.  It must be passed readfds, the + * "in-place" results of a select system call (see select, section 2). + */ + +/* + * Global keeper of rpc service descriptors in use + * dynamic; must be inspected before each call to select  + */ +#ifdef FD_SETSIZE +extern fd_set svc_fdset; +#define svc_fds svc_fdset.fds_bits[0]	/* compatibility */ +#else +extern int svc_fds; +#endif /* def FD_SETSIZE */ + +/* + * a small program implemented by the svc_rpc implementation itself; + * also see clnt.h for protocol numbers. + */ +extern void rpctest_service(); + +extern void	svc_getreq(); +extern void	svc_getreqset();	/* takes fdset instead of int */ +extern void	svc_run(); 	 /* never returns */ + +/* + * Socket to use on svcxxx_create call to get default socket + */ +#define	RPC_ANYSOCK	-1 + +/* + * These are the existing service side transport implementations + */ + +/* + * Memory based rpc for testing and timing. + */ +extern SVCXPRT *svcraw_create(); + +/* + * Udp based rpc. + */ +extern SVCXPRT *svcudp_create(); +extern SVCXPRT *svcudp_bufcreate(); + +/* + * Tcp based rpc. + */ +extern SVCXPRT *svctcp_create(); + + + +#endif !__SVC_HEADER__ diff --git a/lib/librpc/rpc/svc_auth.c b/lib/librpc/rpc/svc_auth.c new file mode 100644 index 000000000000..ab7ab694219f --- /dev/null +++ b/lib/librpc/rpc/svc_auth.c @@ -0,0 +1,114 @@ +#if !defined(lint) && defined(SCCSIDS) +static char sccsid[] = "@(#)svc_auth.c	2.1 88/08/07 4.0 RPCSRC; from 1.19 87/08/11 Copyr 1984 Sun Micro"; +#endif +/* + * Sun RPC is a product of Sun Microsystems, Inc. and is provided for + * unrestricted use provided that this legend is included on all tape + * media and as a part of the software program in whole or part.  Users + * may copy or modify Sun RPC without charge, but are not authorized + * to license or distribute it to anyone else except as part of a product or + * program developed by the user. + *  + * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE + * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR + * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. + *  + * Sun RPC is provided with no support and without any obligation on the + * part of Sun Microsystems, Inc. to assist in its use, correction, + * modification or enhancement. + * + * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE + * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC + * OR ANY PART THEREOF. + * + * In no event will Sun Microsystems, Inc. be liable for any lost revenue + * or profits or other special, indirect and consequential damages, even if + * Sun has been advised of the possibility of such damages. + * + * Sun Microsystems, Inc. + * 2550 Garcia Avenue + * Mountain View, California  94043 + */ + +/* + * svc_auth_nodes.c, Server-side rpc authenticator interface, + * *WITHOUT* DES authentication. + * + * Copyright (C) 1984, Sun Microsystems, Inc. + */ + +#include <rpc/rpc.h> + +/* + * svcauthsw is the bdevsw of server side authentication.  + *  + * Server side authenticators are called from authenticate by + * using the client auth struct flavor field to index into svcauthsw. + * The server auth flavors must implement a routine that looks   + * like:  + *  + *	enum auth_stat + *	flavorx_auth(rqst, msg) + *		register struct svc_req *rqst;  + *		register struct rpc_msg *msg; + * + */ + +enum auth_stat _svcauth_null();		/* no authentication */ +enum auth_stat _svcauth_unix();		/* unix style (uid, gids) */ +enum auth_stat _svcauth_short();	/* short hand unix style */ + +static struct { +	enum auth_stat (*authenticator)(); +} svcauthsw[] = { +	_svcauth_null,			/* AUTH_NULL */ +	_svcauth_unix,			/* AUTH_UNIX */ +	_svcauth_short,			/* AUTH_SHORT */ +}; +#define	AUTH_MAX	2		/* HIGHEST AUTH NUMBER */ + + +/* + * The call rpc message, msg has been obtained from the wire.  The msg contains + * the raw form of credentials and verifiers.  authenticate returns AUTH_OK + * if the msg is successfully authenticated.  If AUTH_OK then the routine also + * does the following things: + * set rqst->rq_xprt->verf to the appropriate response verifier; + * sets rqst->rq_client_cred to the "cooked" form of the credentials. + * + * NB: rqst->rq_cxprt->verf must be pre-alloctaed; + * its length is set appropriately. + * + * The caller still owns and is responsible for msg->u.cmb.cred and + * msg->u.cmb.verf.  The authentication system retains ownership of + * rqst->rq_client_cred, the cooked credentials. + * + * There is an assumption that any flavour less than AUTH_NULL is + * invalid. + */ +enum auth_stat +_authenticate(rqst, msg) +	register struct svc_req *rqst; +	struct rpc_msg *msg; +{ +	register int cred_flavor; + +	rqst->rq_cred = msg->rm_call.cb_cred; +	rqst->rq_xprt->xp_verf.oa_flavor = _null_auth.oa_flavor; +	rqst->rq_xprt->xp_verf.oa_length = 0; +	cred_flavor = rqst->rq_cred.oa_flavor; +	if ((cred_flavor <= AUTH_MAX) && (cred_flavor >= AUTH_NULL)) { +		return ((*(svcauthsw[cred_flavor].authenticator))(rqst, msg)); +	} + +	return (AUTH_REJECTEDCRED); +} + +enum auth_stat +_svcauth_null(/*rqst, msg*/) +	/*struct svc_req *rqst; +	struct rpc_msg *msg;*/ +{ + +	return (AUTH_OK); +} diff --git a/lib/librpc/rpc/svc_auth.h b/lib/librpc/rpc/svc_auth.h new file mode 100644 index 000000000000..a36a01aba8eb --- /dev/null +++ b/lib/librpc/rpc/svc_auth.h @@ -0,0 +1,42 @@ +/* @(#)svc_auth.h	2.1 88/07/29 4.0 RPCSRC */ +/* + * Sun RPC is a product of Sun Microsystems, Inc. and is provided for + * unrestricted use provided that this legend is included on all tape + * media and as a part of the software program in whole or part.  Users + * may copy or modify Sun RPC without charge, but are not authorized + * to license or distribute it to anyone else except as part of a product or + * program developed by the user. + *  + * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE + * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR + * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. + *  + * Sun RPC is provided with no support and without any obligation on the + * part of Sun Microsystems, Inc. to assist in its use, correction, + * modification or enhancement. + *  + * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE + * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC + * OR ANY PART THEREOF. + *  + * In no event will Sun Microsystems, Inc. be liable for any lost revenue + * or profits or other special, indirect and consequential damages, even if + * Sun has been advised of the possibility of such damages. + *  + * Sun Microsystems, Inc. + * 2550 Garcia Avenue + * Mountain View, California  94043 + */ +/*      @(#)svc_auth.h 1.6 86/07/16 SMI      */ + +/* + * svc_auth.h, Service side of rpc authentication. + *  + * Copyright (C) 1984, Sun Microsystems, Inc. + */ + + +/* + * Server side authenticator + */ +extern enum auth_stat _authenticate(); diff --git a/lib/librpc/rpc/svc_auth_unix.c b/lib/librpc/rpc/svc_auth_unix.c new file mode 100644 index 000000000000..ea00b7895fce --- /dev/null +++ b/lib/librpc/rpc/svc_auth_unix.c @@ -0,0 +1,134 @@ +/* @(#)svc_auth_unix.c	2.3 88/08/01 4.0 RPCSRC; from 1.28 88/02/08 SMI */ +/* + * Sun RPC is a product of Sun Microsystems, Inc. and is provided for + * unrestricted use provided that this legend is included on all tape + * media and as a part of the software program in whole or part.  Users + * may copy or modify Sun RPC without charge, but are not authorized + * to license or distribute it to anyone else except as part of a product or + * program developed by the user. + *  + * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE + * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR + * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. + *  + * Sun RPC is provided with no support and without any obligation on the + * part of Sun Microsystems, Inc. to assist in its use, correction, + * modification or enhancement. + *  + * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE + * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC + * OR ANY PART THEREOF. + *  + * In no event will Sun Microsystems, Inc. be liable for any lost revenue + * or profits or other special, indirect and consequential damages, even if + * Sun has been advised of the possibility of such damages. + *  + * Sun Microsystems, Inc. + * 2550 Garcia Avenue + * Mountain View, California  94043 + */ +#if !defined(lint) && defined(SCCSIDS) +static char sccsid[] = "@(#)svc_auth_unix.c 1.28 88/02/08 Copyr 1984 Sun Micro"; +#endif + +/* + * svc_auth_unix.c + * Handles UNIX flavor authentication parameters on the service side of rpc. + * There are two svc auth implementations here: AUTH_UNIX and AUTH_SHORT. + * _svcauth_unix does full blown unix style uid,gid+gids auth, + * _svcauth_short uses a shorthand auth to index into a cache of longhand auths. + * Note: the shorthand has been gutted for efficiency. + * + * Copyright (C) 1984, Sun Microsystems, Inc. + */ + +#include <stdio.h> +#include <rpc/rpc.h> + +/* + * Unix longhand authenticator + */ +enum auth_stat +_svcauth_unix(rqst, msg) +	register struct svc_req *rqst; +	register struct rpc_msg *msg; +{ +	register enum auth_stat stat; +	XDR xdrs; +	register struct authunix_parms *aup; +	register long *buf; +	struct area { +		struct authunix_parms area_aup; +		char area_machname[MAX_MACHINE_NAME+1]; +		int area_gids[NGRPS]; +	} *area; +	u_int auth_len; +	int str_len, gid_len; +	register int i; + +	area = (struct area *) rqst->rq_clntcred; +	aup = &area->area_aup; +	aup->aup_machname = area->area_machname; +	aup->aup_gids = area->area_gids; +	auth_len = (u_int)msg->rm_call.cb_cred.oa_length; +	xdrmem_create(&xdrs, msg->rm_call.cb_cred.oa_base, auth_len,XDR_DECODE); +	buf = XDR_INLINE(&xdrs, auth_len); +	if (buf != NULL) { +		aup->aup_time = IXDR_GET_LONG(buf); +		str_len = IXDR_GET_U_LONG(buf); +		if (str_len > MAX_MACHINE_NAME) { +			stat = AUTH_BADCRED; +			goto done; +		} +		bcopy((caddr_t)buf, aup->aup_machname, (u_int)str_len); +		aup->aup_machname[str_len] = 0; +		str_len = RNDUP(str_len); +		buf += str_len / sizeof (long); +		aup->aup_uid = IXDR_GET_LONG(buf); +		aup->aup_gid = IXDR_GET_LONG(buf); +		gid_len = IXDR_GET_U_LONG(buf); +		if (gid_len > NGRPS) { +			stat = AUTH_BADCRED; +			goto done; +		} +		aup->aup_len = gid_len; +		for (i = 0; i < gid_len; i++) { +			aup->aup_gids[i] = IXDR_GET_LONG(buf); +		} +		/* +		 * five is the smallest unix credentials structure - +		 * timestamp, hostname len (0), uid, gid, and gids len (0). +		 */ +		if ((5 + gid_len) * BYTES_PER_XDR_UNIT + str_len > auth_len) { +			(void) printf("bad auth_len gid %d str %d auth %d\n", +			    gid_len, str_len, auth_len); +			stat = AUTH_BADCRED; +			goto done; +		} +	} else if (! xdr_authunix_parms(&xdrs, aup)) { +		xdrs.x_op = XDR_FREE; +		(void)xdr_authunix_parms(&xdrs, aup); +		stat = AUTH_BADCRED; +		goto done; +	} +	rqst->rq_xprt->xp_verf.oa_flavor = AUTH_NULL; +	rqst->rq_xprt->xp_verf.oa_length = 0; +	stat = AUTH_OK; +done: +	XDR_DESTROY(&xdrs); +	return (stat); +} + + +/* + * Shorthand unix authenticator + * Looks up longhand in a cache. + */ +/*ARGSUSED*/ +enum auth_stat  +_svcauth_short(rqst, msg) +	struct svc_req *rqst; +	struct rpc_msg *msg; +{ +	return (AUTH_REJECTEDCRED); +} diff --git a/lib/librpc/rpc/svc_raw.c b/lib/librpc/rpc/svc_raw.c new file mode 100644 index 000000000000..1170ecec83f2 --- /dev/null +++ b/lib/librpc/rpc/svc_raw.c @@ -0,0 +1,166 @@ +/* @(#)svc_raw.c	2.1 88/07/29 4.0 RPCSRC */ +/* + * Sun RPC is a product of Sun Microsystems, Inc. and is provided for + * unrestricted use provided that this legend is included on all tape + * media and as a part of the software program in whole or part.  Users + * may copy or modify Sun RPC without charge, but are not authorized + * to license or distribute it to anyone else except as part of a product or + * program developed by the user. + *  + * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE + * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR + * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. + *  + * Sun RPC is provided with no support and without any obligation on the + * part of Sun Microsystems, Inc. to assist in its use, correction, + * modification or enhancement. + *  + * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE + * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC + * OR ANY PART THEREOF. + *  + * In no event will Sun Microsystems, Inc. be liable for any lost revenue + * or profits or other special, indirect and consequential damages, even if + * Sun has been advised of the possibility of such damages. + *  + * Sun Microsystems, Inc. + * 2550 Garcia Avenue + * Mountain View, California  94043 + */ +#if !defined(lint) && defined(SCCSIDS) +static char sccsid[] = "@(#)svc_raw.c 1.15 87/08/11 Copyr 1984 Sun Micro"; +#endif + +/* + * svc_raw.c,   This a toy for simple testing and timing. + * Interface to create an rpc client and server in the same UNIX process. + * This lets us similate rpc and get rpc (round trip) overhead, without + * any interference from the kernal. + * + * Copyright (C) 1984, Sun Microsystems, Inc. + */ + +#include <rpc/rpc.h> + + +/* + * This is the "network" that we will be moving data over + */ +static struct svcraw_private { +	char	_raw_buf[UDPMSGSIZE]; +	SVCXPRT	server; +	XDR	xdr_stream; +	char	verf_body[MAX_AUTH_BYTES]; +} *svcraw_private; + +static bool_t		svcraw_recv(); +static enum xprt_stat 	svcraw_stat(); +static bool_t		svcraw_getargs(); +static bool_t		svcraw_reply(); +static bool_t		svcraw_freeargs(); +static void		svcraw_destroy(); + +static struct xp_ops server_ops = { +	svcraw_recv, +	svcraw_stat, +	svcraw_getargs, +	svcraw_reply, +	svcraw_freeargs, +	svcraw_destroy +}; + +SVCXPRT * +svcraw_create() +{ +	register struct svcraw_private *srp = svcraw_private; + +	if (srp == 0) { +		srp = (struct svcraw_private *)calloc(1, sizeof (*srp)); +		if (srp == 0) +			return (0); +	} +	srp->server.xp_sock = 0; +	srp->server.xp_port = 0; +	srp->server.xp_ops = &server_ops; +	srp->server.xp_verf.oa_base = srp->verf_body; +	xdrmem_create(&srp->xdr_stream, srp->_raw_buf, UDPMSGSIZE, XDR_FREE); +	return (&srp->server); +} + +static enum xprt_stat +svcraw_stat() +{ + +	return (XPRT_IDLE); +} + +static bool_t +svcraw_recv(xprt, msg) +	SVCXPRT *xprt; +	struct rpc_msg *msg; +{ +	register struct svcraw_private *srp = svcraw_private; +	register XDR *xdrs; + +	if (srp == 0) +		return (0); +	xdrs = &srp->xdr_stream; +	xdrs->x_op = XDR_DECODE; +	XDR_SETPOS(xdrs, 0); +	if (! xdr_callmsg(xdrs, msg)) +	       return (FALSE); +	return (TRUE); +} + +static bool_t +svcraw_reply(xprt, msg) +	SVCXPRT *xprt; +	struct rpc_msg *msg; +{ +	register struct svcraw_private *srp = svcraw_private; +	register XDR *xdrs; + +	if (srp == 0) +		return (FALSE); +	xdrs = &srp->xdr_stream; +	xdrs->x_op = XDR_ENCODE; +	XDR_SETPOS(xdrs, 0); +	if (! xdr_replymsg(xdrs, msg)) +	       return (FALSE); +	(void)XDR_GETPOS(xdrs);  /* called just for overhead */ +	return (TRUE); +} + +static bool_t +svcraw_getargs(xprt, xdr_args, args_ptr) +	SVCXPRT *xprt; +	xdrproc_t xdr_args; +	caddr_t args_ptr; +{ +	register struct svcraw_private *srp = svcraw_private; + +	if (srp == 0) +		return (FALSE); +	return ((*xdr_args)(&srp->xdr_stream, args_ptr)); +} + +static bool_t +svcraw_freeargs(xprt, xdr_args, args_ptr) +	SVCXPRT *xprt; +	xdrproc_t xdr_args; +	caddr_t args_ptr; +{  +	register struct svcraw_private *srp = svcraw_private; +	register XDR *xdrs; + +	if (srp == 0) +		return (FALSE); +	xdrs = &srp->xdr_stream; +	xdrs->x_op = XDR_FREE; +	return ((*xdr_args)(xdrs, args_ptr)); +}  + +static void +svcraw_destroy() +{ +} diff --git a/lib/librpc/rpc/svc_run.c b/lib/librpc/rpc/svc_run.c new file mode 100644 index 000000000000..c1c3e0478114 --- /dev/null +++ b/lib/librpc/rpc/svc_run.c @@ -0,0 +1,72 @@ +/* @(#)svc_run.c	2.1 88/07/29 4.0 RPCSRC */ +#if !defined(lint) && defined(SCCSIDS) +static char sccsid[] = "@(#)svc_run.c 1.1 87/10/13 Copyr 1984 Sun Micro"; +#endif + +/* + * Sun RPC is a product of Sun Microsystems, Inc. and is provided for + * unrestricted use provided that this legend is included on all tape + * media and as a part of the software program in whole or part.  Users + * may copy or modify Sun RPC without charge, but are not authorized + * to license or distribute it to anyone else except as part of a product or + * program developed by the user. + *  + * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE + * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR + * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. + *  + * Sun RPC is provided with no support and without any obligation on the + * part of Sun Microsystems, Inc. to assist in its use, correction, + * modification or enhancement. + *  + * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE + * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC + * OR ANY PART THEREOF. + *  + * In no event will Sun Microsystems, Inc. be liable for any lost revenue + * or profits or other special, indirect and consequential damages, even if + * Sun has been advised of the possibility of such damages. + *  + * Sun Microsystems, Inc. + * 2550 Garcia Avenue + * Mountain View, California  94043 + */ + +/* + * This is the rpc server side idle loop + * Wait for input, call server program. + */ +#include <rpc/rpc.h> +#include <sys/errno.h> + +void +svc_run() +{ +#ifdef FD_SETSIZE +	fd_set readfds; +#else +      int readfds; +#endif /* def FD_SETSIZE */ +	extern int errno; + +	for (;;) { +#ifdef FD_SETSIZE +		readfds = svc_fdset; +#else +		readfds = svc_fds; +#endif /* def FD_SETSIZE */ +		switch (select(_rpc_dtablesize(), &readfds, (int *)0, (int *)0, +			       (struct timeval *)0)) { +		case -1: +			if (errno == EINTR) { +				continue; +			} +			perror("svc_run: - select failed"); +			return; +		case 0: +			continue; +		default: +			svc_getreqset(&readfds); +		} +	} +} diff --git a/lib/librpc/rpc/svc_simple.c b/lib/librpc/rpc/svc_simple.c new file mode 100644 index 000000000000..d6bcbd3c040d --- /dev/null +++ b/lib/librpc/rpc/svc_simple.c @@ -0,0 +1,143 @@ +/* @(#)svc_simple.c	2.2 88/08/01 4.0 RPCSRC */ +/* + * Sun RPC is a product of Sun Microsystems, Inc. and is provided for + * unrestricted use provided that this legend is included on all tape + * media and as a part of the software program in whole or part.  Users + * may copy or modify Sun RPC without charge, but are not authorized + * to license or distribute it to anyone else except as part of a product or + * program developed by the user. + *  + * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE + * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR + * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. + *  + * Sun RPC is provided with no support and without any obligation on the + * part of Sun Microsystems, Inc. to assist in its use, correction, + * modification or enhancement. + *  + * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE + * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC + * OR ANY PART THEREOF. + *  + * In no event will Sun Microsystems, Inc. be liable for any lost revenue + * or profits or other special, indirect and consequential damages, even if + * Sun has been advised of the possibility of such damages. + *  + * Sun Microsystems, Inc. + * 2550 Garcia Avenue + * Mountain View, California  94043 + */ +#if !defined(lint) && defined(SCCSIDS) +static char sccsid[] = "@(#)svc_simple.c 1.18 87/08/11 Copyr 1984 Sun Micro"; +#endif + +/*  + * svc_simple.c + * Simplified front end to rpc. + * + * Copyright (C) 1984, Sun Microsystems, Inc. + */ + +#include <stdio.h> +#include <rpc/rpc.h> +#include <sys/socket.h> +#include <netdb.h> + +static struct proglst { +	char *(*p_progname)(); +	int  p_prognum; +	int  p_procnum; +	xdrproc_t p_inproc, p_outproc; +	struct proglst *p_nxt; +} *proglst; +static void universal(); +static SVCXPRT *transp; +struct proglst *pl; + +registerrpc(prognum, versnum, procnum, progname, inproc, outproc) +	char *(*progname)(); +	xdrproc_t inproc, outproc; +{ +	 +	if (procnum == NULLPROC) { +		(void) fprintf(stderr, +		    "can't reassign procedure number %d\n", NULLPROC); +		return (-1); +	} +	if (transp == 0) { +		transp = svcudp_create(RPC_ANYSOCK); +		if (transp == NULL) { +			(void) fprintf(stderr, "couldn't create an rpc server\n"); +			return (-1); +		} +	} +	(void) pmap_unset((u_long)prognum, (u_long)versnum); +	if (!svc_register(transp, (u_long)prognum, (u_long)versnum,  +	    universal, IPPROTO_UDP)) { +	    	(void) fprintf(stderr, "couldn't register prog %d vers %d\n", +		    prognum, versnum); +		return (-1); +	} +	pl = (struct proglst *)malloc(sizeof(struct proglst)); +	if (pl == NULL) { +		(void) fprintf(stderr, "registerrpc: out of memory\n"); +		return (-1); +	} +	pl->p_progname = progname; +	pl->p_prognum = prognum; +	pl->p_procnum = procnum; +	pl->p_inproc = inproc; +	pl->p_outproc = outproc; +	pl->p_nxt = proglst; +	proglst = pl; +	return (0); +} + +static void +universal(rqstp, transp) +	struct svc_req *rqstp; +	SVCXPRT *transp; +{ +	int prog, proc; +	char *outdata; +	char xdrbuf[UDPMSGSIZE]; +	struct proglst *pl; + +	/*  +	 * enforce "procnum 0 is echo" convention +	 */ +	if (rqstp->rq_proc == NULLPROC) { +		if (svc_sendreply(transp, xdr_void, (char *)NULL) == FALSE) { +			(void) fprintf(stderr, "xxx\n"); +			exit(1); +		} +		return; +	} +	prog = rqstp->rq_prog; +	proc = rqstp->rq_proc; +	for (pl = proglst; pl != NULL; pl = pl->p_nxt) +		if (pl->p_prognum == prog && pl->p_procnum == proc) { +			/* decode arguments into a CLEAN buffer */ +			bzero(xdrbuf, sizeof(xdrbuf)); /* required ! */ +			if (!svc_getargs(transp, pl->p_inproc, xdrbuf)) { +				svcerr_decode(transp); +				return; +			} +			outdata = (*(pl->p_progname))(xdrbuf); +			if (outdata == NULL && pl->p_outproc != xdr_void) +				/* there was an error */ +				return; +			if (!svc_sendreply(transp, pl->p_outproc, outdata)) { +				(void) fprintf(stderr, +				    "trouble replying to prog %d\n", +				    pl->p_prognum); +				exit(1); +			} +			/* free the decoded arguments */ +			(void)svc_freeargs(transp, pl->p_inproc, xdrbuf); +			return; +		} +	(void) fprintf(stderr, "never registered prog %d\n", prog); +	exit(1); +} + diff --git a/lib/librpc/rpc/svc_tcp.c b/lib/librpc/rpc/svc_tcp.c new file mode 100644 index 000000000000..efa21dcdcd7a --- /dev/null +++ b/lib/librpc/rpc/svc_tcp.c @@ -0,0 +1,419 @@ +/* @(#)svc_tcp.c	2.2 88/08/01 4.0 RPCSRC */ +/* + * Sun RPC is a product of Sun Microsystems, Inc. and is provided for + * unrestricted use provided that this legend is included on all tape + * media and as a part of the software program in whole or part.  Users + * may copy or modify Sun RPC without charge, but are not authorized + * to license or distribute it to anyone else except as part of a product or + * program developed by the user. + *  + * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE + * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR + * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. + *  + * Sun RPC is provided with no support and without any obligation on the + * part of Sun Microsystems, Inc. to assist in its use, correction, + * modification or enhancement. + *  + * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE + * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC + * OR ANY PART THEREOF. + *  + * In no event will Sun Microsystems, Inc. be liable for any lost revenue + * or profits or other special, indirect and consequential damages, even if + * Sun has been advised of the possibility of such damages. + *  + * Sun Microsystems, Inc. + * 2550 Garcia Avenue + * Mountain View, California  94043 + */ +#if !defined(lint) && defined(SCCSIDS) +static char sccsid[] = "@(#)svc_tcp.c 1.21 87/08/11 Copyr 1984 Sun Micro"; +#endif + +/* + * svc_tcp.c, Server side for TCP/IP based RPC.  + * + * Copyright (C) 1984, Sun Microsystems, Inc. + * + * Actually implements two flavors of transporter - + * a tcp rendezvouser (a listner and connection establisher) + * and a record/tcp stream. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <rpc/rpc.h> +#include <sys/socket.h> +#include <errno.h> +extern errno; + +/* + * Ops vector for TCP/IP based rpc service handle + */ +static bool_t		svctcp_recv(); +static enum xprt_stat	svctcp_stat(); +static bool_t		svctcp_getargs(); +static bool_t		svctcp_reply(); +static bool_t		svctcp_freeargs(); +static void		svctcp_destroy(); + +static struct xp_ops svctcp_op = { +	svctcp_recv, +	svctcp_stat, +	svctcp_getargs, +	svctcp_reply, +	svctcp_freeargs, +	svctcp_destroy +}; + +/* + * Ops vector for TCP/IP rendezvous handler + */ +static bool_t		rendezvous_request(); +static enum xprt_stat	rendezvous_stat(); + +static struct xp_ops svctcp_rendezvous_op = { +	rendezvous_request, +	rendezvous_stat, +	(bool_t (*)())abort, +	(bool_t (*)())abort, +	(bool_t (*)())abort, +	svctcp_destroy +}; + +static int readtcp(), writetcp(); +static SVCXPRT *makefd_xprt(); + +struct tcp_rendezvous { /* kept in xprt->xp_p1 */ +	u_int sendsize; +	u_int recvsize; +}; + +struct tcp_conn {  /* kept in xprt->xp_p1 */ +	enum xprt_stat strm_stat; +	u_long x_id; +	XDR xdrs; +	char verf_body[MAX_AUTH_BYTES]; +}; + +/* + * Usage: + *	xprt = svctcp_create(sock, send_buf_size, recv_buf_size); + * + * Creates, registers, and returns a (rpc) tcp based transporter. + * Once *xprt is initialized, it is registered as a transporter + * see (svc.h, xprt_register).  This routine returns + * a NULL if a problem occurred. + * + * If sock<0 then a socket is created, else sock is used. + * If the socket, sock is not bound to a port then svctcp_create + * binds it to an arbitrary port.  The routine then starts a tcp + * listener on the socket's associated port.  In any (successful) case, + * xprt->xp_sock is the registered socket number and xprt->xp_port is the + * associated port number. + * + * Since tcp streams do buffered io similar to stdio, the caller can specify + * how big the send and receive buffers are via the second and third parms; + * 0 => use the system default. + */ +SVCXPRT * +svctcp_create(sock, sendsize, recvsize) +	register int sock; +	u_int sendsize; +	u_int recvsize; +{ +	bool_t madesock = FALSE; +	register SVCXPRT *xprt; +	register struct tcp_rendezvous *r; +	struct sockaddr_in addr; +	int len = sizeof(struct sockaddr_in); + +	if (sock == RPC_ANYSOCK) { +		if ((sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) { +			perror("svctcp_.c - udp socket creation problem"); +			return ((SVCXPRT *)NULL); +		} +		madesock = TRUE; +	} +	bzero((char *)&addr, sizeof (addr)); +	addr.sin_family = AF_INET; +	if (bindresvport(sock, &addr)) { +		addr.sin_port = 0; +		(void)bind(sock, (struct sockaddr *)&addr, len); +	} +	if ((getsockname(sock, (struct sockaddr *)&addr, &len) != 0)  || +	    (listen(sock, 2) != 0)) { +		perror("svctcp_.c - cannot getsockname or listen"); +		if (madesock) +		       (void)close(sock); +		return ((SVCXPRT *)NULL); +	} +	r = (struct tcp_rendezvous *)mem_alloc(sizeof(*r)); +	if (r == NULL) { +		(void) fprintf(stderr, "svctcp_create: out of memory\n"); +		return (NULL); +	} +	r->sendsize = sendsize; +	r->recvsize = recvsize; +	xprt = (SVCXPRT *)mem_alloc(sizeof(SVCXPRT)); +	if (xprt == NULL) { +		(void) fprintf(stderr, "svctcp_create: out of memory\n"); +		return (NULL); +	} +	xprt->xp_p2 = NULL; +	xprt->xp_p1 = (caddr_t)r; +	xprt->xp_verf = _null_auth; +	xprt->xp_ops = &svctcp_rendezvous_op; +	xprt->xp_port = ntohs(addr.sin_port); +	xprt->xp_sock = sock; +	xprt_register(xprt); +	return (xprt); +} + +/* + * Like svtcp_create(), except the routine takes any *open* UNIX file + * descriptor as its first input. + */ +SVCXPRT * +svcfd_create(fd, sendsize, recvsize) +	int fd; +	u_int sendsize; +	u_int recvsize; +{ + +	return (makefd_xprt(fd, sendsize, recvsize)); +} + +static SVCXPRT * +makefd_xprt(fd, sendsize, recvsize) +	int fd; +	u_int sendsize; +	u_int recvsize; +{ +	register SVCXPRT *xprt; +	register struct tcp_conn *cd; +  +	xprt = (SVCXPRT *)mem_alloc(sizeof(SVCXPRT)); +	if (xprt == (SVCXPRT *)NULL) { +		(void) fprintf(stderr, "svc_tcp: makefd_xprt: out of memory\n"); +		goto done; +	} +	cd = (struct tcp_conn *)mem_alloc(sizeof(struct tcp_conn)); +	if (cd == (struct tcp_conn *)NULL) { +		(void) fprintf(stderr, "svc_tcp: makefd_xprt: out of memory\n"); +		mem_free((char *) xprt, sizeof(SVCXPRT)); +		xprt = (SVCXPRT *)NULL; +		goto done; +	} +	cd->strm_stat = XPRT_IDLE; +	xdrrec_create(&(cd->xdrs), sendsize, recvsize, +	    (caddr_t)xprt, readtcp, writetcp); +	xprt->xp_p2 = NULL; +	xprt->xp_p1 = (caddr_t)cd; +	xprt->xp_verf.oa_base = cd->verf_body; +	xprt->xp_addrlen = 0; +	xprt->xp_ops = &svctcp_op;  /* truely deals with calls */ +	xprt->xp_port = 0;  /* this is a connection, not a rendezvouser */ +	xprt->xp_sock = fd; +	xprt_register(xprt); +    done: +	return (xprt); +} + +static bool_t +rendezvous_request(xprt) +	register SVCXPRT *xprt; +{ +	int sock; +	struct tcp_rendezvous *r; +	struct sockaddr_in addr; +	int len; + +	r = (struct tcp_rendezvous *)xprt->xp_p1; +    again: +	len = sizeof(struct sockaddr_in); +	if ((sock = accept(xprt->xp_sock, (struct sockaddr *)&addr, +	    &len)) < 0) { +		if (errno == EINTR) +			goto again; +	       return (FALSE); +	} +	/* +	 * make a new transporter (re-uses xprt) +	 */ +	xprt = makefd_xprt(sock, r->sendsize, r->recvsize); +	xprt->xp_raddr = addr; +	xprt->xp_addrlen = len; +	return (FALSE); /* there is never an rpc msg to be processed */ +} + +static enum xprt_stat +rendezvous_stat() +{ + +	return (XPRT_IDLE); +} + +static void +svctcp_destroy(xprt) +	register SVCXPRT *xprt; +{ +	register struct tcp_conn *cd = (struct tcp_conn *)xprt->xp_p1; + +	xprt_unregister(xprt); +	(void)close(xprt->xp_sock); +	if (xprt->xp_port != 0) { +		/* a rendezvouser socket */ +		xprt->xp_port = 0; +	} else { +		/* an actual connection socket */ +		XDR_DESTROY(&(cd->xdrs)); +	} +	mem_free((caddr_t)cd, sizeof(struct tcp_conn)); +	mem_free((caddr_t)xprt, sizeof(SVCXPRT)); +} + +/* + * All read operations timeout after 35 seconds. + * A timeout is fatal for the connection. + */ +static struct timeval wait_per_try = { 35, 0 }; + +/* + * reads data from the tcp conection. + * any error is fatal and the connection is closed. + * (And a read of zero bytes is a half closed stream => error.) + */ +static int +readtcp(xprt, buf, len) +	register SVCXPRT *xprt; +	caddr_t buf; +	register int len; +{ +	register int sock = xprt->xp_sock; +#ifdef FD_SETSIZE +	fd_set mask; +	fd_set readfds; + +	FD_ZERO(&mask); +	FD_SET(sock, &mask); +#else +	register int mask = 1 << sock; +	int readfds; +#endif /* def FD_SETSIZE */ +	do { +		readfds = mask; +		if (select(_rpc_dtablesize(), &readfds, (int*)NULL, (int*)NULL,  +			   &wait_per_try) <= 0) { +			if (errno == EINTR) { +				continue; +			} +			goto fatal_err; +		} +#ifdef FD_SETSIZE +	} while (!FD_ISSET(sock, &readfds)); +#else +	} while (readfds != mask); +#endif /* def FD_SETSIZE */ +	if ((len = read(sock, buf, len)) > 0) { +		return (len); +	} +fatal_err: +	((struct tcp_conn *)(xprt->xp_p1))->strm_stat = XPRT_DIED; +	return (-1); +} + +/* + * writes data to the tcp connection. + * Any error is fatal and the connection is closed. + */ +static int +writetcp(xprt, buf, len) +	register SVCXPRT *xprt; +	caddr_t buf; +	int len; +{ +	register int i, cnt; + +	for (cnt = len; cnt > 0; cnt -= i, buf += i) { +		if ((i = write(xprt->xp_sock, buf, cnt)) < 0) { +			((struct tcp_conn *)(xprt->xp_p1))->strm_stat = +			    XPRT_DIED; +			return (-1); +		} +	} +	return (len); +} + +static enum xprt_stat +svctcp_stat(xprt) +	SVCXPRT *xprt; +{ +	register struct tcp_conn *cd = +	    (struct tcp_conn *)(xprt->xp_p1); + +	if (cd->strm_stat == XPRT_DIED) +		return (XPRT_DIED); +	if (! xdrrec_eof(&(cd->xdrs))) +		return (XPRT_MOREREQS); +	return (XPRT_IDLE); +} + +static bool_t +svctcp_recv(xprt, msg) +	SVCXPRT *xprt; +	register struct rpc_msg *msg; +{ +	register struct tcp_conn *cd = +	    (struct tcp_conn *)(xprt->xp_p1); +	register XDR *xdrs = &(cd->xdrs); + +	xdrs->x_op = XDR_DECODE; +	(void)xdrrec_skiprecord(xdrs); +	if (xdr_callmsg(xdrs, msg)) { +		cd->x_id = msg->rm_xid; +		return (TRUE); +	} +	return (FALSE); +} + +static bool_t +svctcp_getargs(xprt, xdr_args, args_ptr) +	SVCXPRT *xprt; +	xdrproc_t xdr_args; +	caddr_t args_ptr; +{ + +	return ((*xdr_args)(&(((struct tcp_conn *)(xprt->xp_p1))->xdrs), args_ptr)); +} + +static bool_t +svctcp_freeargs(xprt, xdr_args, args_ptr) +	SVCXPRT *xprt; +	xdrproc_t xdr_args; +	caddr_t args_ptr; +{ +	register XDR *xdrs = +	    &(((struct tcp_conn *)(xprt->xp_p1))->xdrs); + +	xdrs->x_op = XDR_FREE; +	return ((*xdr_args)(xdrs, args_ptr)); +} + +static bool_t +svctcp_reply(xprt, msg) +	SVCXPRT *xprt; +	register struct rpc_msg *msg; +{ +	register struct tcp_conn *cd = +	    (struct tcp_conn *)(xprt->xp_p1); +	register XDR *xdrs = &(cd->xdrs); +	register bool_t stat; + +	xdrs->x_op = XDR_ENCODE; +	msg->rm_xid = cd->x_id; +	stat = xdr_replymsg(xdrs, msg); +	(void)xdrrec_endofrecord(xdrs, TRUE); +	return (stat); +} diff --git a/lib/librpc/rpc/svc_udp.c b/lib/librpc/rpc/svc_udp.c new file mode 100644 index 000000000000..cc5266a65de1 --- /dev/null +++ b/lib/librpc/rpc/svc_udp.c @@ -0,0 +1,477 @@ +/* @(#)svc_udp.c	2.2 88/07/29 4.0 RPCSRC */ +/* + * Sun RPC is a product of Sun Microsystems, Inc. and is provided for + * unrestricted use provided that this legend is included on all tape + * media and as a part of the software program in whole or part.  Users + * may copy or modify Sun RPC without charge, but are not authorized + * to license or distribute it to anyone else except as part of a product or + * program developed by the user. + *  + * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE + * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR + * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. + *  + * Sun RPC is provided with no support and without any obligation on the + * part of Sun Microsystems, Inc. to assist in its use, correction, + * modification or enhancement. + *  + * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE + * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC + * OR ANY PART THEREOF. + *  + * In no event will Sun Microsystems, Inc. be liable for any lost revenue + * or profits or other special, indirect and consequential damages, even if + * Sun has been advised of the possibility of such damages. + *  + * Sun Microsystems, Inc. + * 2550 Garcia Avenue + * Mountain View, California  94043 + */ +#if !defined(lint) && defined(SCCSIDS) +static char sccsid[] = "@(#)svc_udp.c 1.24 87/08/11 Copyr 1984 Sun Micro"; +#endif + +/* + * svc_udp.c, + * Server side for UDP/IP based RPC.  (Does some caching in the hopes of + * achieving execute-at-most-once semantics.) + * + * Copyright (C) 1984, Sun Microsystems, Inc. + */ + +#include <stdio.h> +#include <rpc/rpc.h> +#include <sys/socket.h> +#include <errno.h> + + +#define rpc_buffer(xprt) ((xprt)->xp_p1) +#define MAX(a, b)     ((a > b) ? a : b) + +static bool_t		svcudp_recv(); +static bool_t		svcudp_reply(); +static enum xprt_stat	svcudp_stat(); +static bool_t		svcudp_getargs(); +static bool_t		svcudp_freeargs(); +static void		svcudp_destroy(); + +static struct xp_ops svcudp_op = { +	svcudp_recv, +	svcudp_stat, +	svcudp_getargs, +	svcudp_reply, +	svcudp_freeargs, +	svcudp_destroy +}; + +extern int errno; + +/* + * kept in xprt->xp_p2 + */ +struct svcudp_data { +	u_int   su_iosz;	/* byte size of send.recv buffer */ +	u_long	su_xid;		/* transaction id */ +	XDR	su_xdrs;	/* XDR handle */ +	char	su_verfbody[MAX_AUTH_BYTES];	/* verifier body */ +	char * 	su_cache;	/* cached data, NULL if no cache */ +}; +#define	su_data(xprt)	((struct svcudp_data *)(xprt->xp_p2)) + +/* + * Usage: + *	xprt = svcudp_create(sock); + * + * If sock<0 then a socket is created, else sock is used. + * If the socket, sock is not bound to a port then svcudp_create + * binds it to an arbitrary port.  In any (successful) case, + * xprt->xp_sock is the registered socket number and xprt->xp_port is the + * associated port number. + * Once *xprt is initialized, it is registered as a transporter; + * see (svc.h, xprt_register). + * The routines returns NULL if a problem occurred. + */ +SVCXPRT * +svcudp_bufcreate(sock, sendsz, recvsz) +	register int sock; +	u_int sendsz, recvsz; +{ +	bool_t madesock = FALSE; +	register SVCXPRT *xprt; +	register struct svcudp_data *su; +	struct sockaddr_in addr; +	int len = sizeof(struct sockaddr_in); + +	if (sock == RPC_ANYSOCK) { +		if ((sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) { +			perror("svcudp_create: socket creation problem"); +			return ((SVCXPRT *)NULL); +		} +		madesock = TRUE; +	} +	bzero((char *)&addr, sizeof (addr)); +	addr.sin_family = AF_INET; +	if (bindresvport(sock, &addr)) { +		addr.sin_port = 0; +		(void)bind(sock, (struct sockaddr *)&addr, len); +	} +	if (getsockname(sock, (struct sockaddr *)&addr, &len) != 0) { +		perror("svcudp_create - cannot getsockname"); +		if (madesock) +			(void)close(sock); +		return ((SVCXPRT *)NULL); +	} +	xprt = (SVCXPRT *)mem_alloc(sizeof(SVCXPRT)); +	if (xprt == NULL) { +		(void)fprintf(stderr, "svcudp_create: out of memory\n"); +		return (NULL); +	} +	su = (struct svcudp_data *)mem_alloc(sizeof(*su)); +	if (su == NULL) { +		(void)fprintf(stderr, "svcudp_create: out of memory\n"); +		return (NULL); +	} +	su->su_iosz = ((MAX(sendsz, recvsz) + 3) / 4) * 4; +	if ((rpc_buffer(xprt) = mem_alloc(su->su_iosz)) == NULL) { +		(void)fprintf(stderr, "svcudp_create: out of memory\n"); +		return (NULL); +	} +	xdrmem_create( +	    &(su->su_xdrs), rpc_buffer(xprt), su->su_iosz, XDR_DECODE); +	su->su_cache = NULL; +	xprt->xp_p2 = (caddr_t)su; +	xprt->xp_verf.oa_base = su->su_verfbody; +	xprt->xp_ops = &svcudp_op; +	xprt->xp_port = ntohs(addr.sin_port); +	xprt->xp_sock = sock; +	xprt_register(xprt); +	return (xprt); +} + +SVCXPRT * +svcudp_create(sock) +	int sock; +{ + +	return(svcudp_bufcreate(sock, UDPMSGSIZE, UDPMSGSIZE)); +} + +static enum xprt_stat +svcudp_stat(xprt) +	SVCXPRT *xprt; +{ + +	return (XPRT_IDLE);  +} + +static bool_t +svcudp_recv(xprt, msg) +	register SVCXPRT *xprt; +	struct rpc_msg *msg; +{ +	register struct svcudp_data *su = su_data(xprt); +	register XDR *xdrs = &(su->su_xdrs); +	register int rlen; +	char *reply; +	u_long replylen; +	static int cache_get(); + +    again: +	xprt->xp_addrlen = sizeof(struct sockaddr_in); +	rlen = recvfrom(xprt->xp_sock, rpc_buffer(xprt), (int) su->su_iosz, +	    0, (struct sockaddr *)&(xprt->xp_raddr), &(xprt->xp_addrlen)); +	if (rlen == -1 && errno == EINTR) +		goto again; +	if (rlen < (int)(4*sizeof(u_long))) +		return (FALSE); +	xdrs->x_op = XDR_DECODE; +	XDR_SETPOS(xdrs, 0); +	if (! xdr_callmsg(xdrs, msg)) +		return (FALSE); +	su->su_xid = msg->rm_xid; +	if (su->su_cache != NULL) { +		if (cache_get(xprt, msg, &reply, &replylen)) { +			(void) sendto(xprt->xp_sock, reply, (int) replylen, 0, +			  (struct sockaddr *) &xprt->xp_raddr, xprt->xp_addrlen); +			return (TRUE); +		} +	} +	return (TRUE); +} + +static bool_t +svcudp_reply(xprt, msg) +	register SVCXPRT *xprt;  +	struct rpc_msg *msg;  +{ +	register struct svcudp_data *su = su_data(xprt); +	register XDR *xdrs = &(su->su_xdrs); +	register int slen; +	register bool_t stat = FALSE; +	static void cache_set(); + +	xdrs->x_op = XDR_ENCODE; +	XDR_SETPOS(xdrs, 0); +	msg->rm_xid = su->su_xid; +	if (xdr_replymsg(xdrs, msg)) { +		slen = (int)XDR_GETPOS(xdrs); +		if (sendto(xprt->xp_sock, rpc_buffer(xprt), slen, 0, +		    (struct sockaddr *)&(xprt->xp_raddr), xprt->xp_addrlen) +		    == slen) { +			stat = TRUE; +			if (su->su_cache && slen >= 0) { +				cache_set(xprt, (u_long) slen); +			} +		} +	} +	return (stat); +} + +static bool_t +svcudp_getargs(xprt, xdr_args, args_ptr) +	SVCXPRT *xprt; +	xdrproc_t xdr_args; +	caddr_t args_ptr; +{ + +	return ((*xdr_args)(&(su_data(xprt)->su_xdrs), args_ptr)); +} + +static bool_t +svcudp_freeargs(xprt, xdr_args, args_ptr) +	SVCXPRT *xprt; +	xdrproc_t xdr_args; +	caddr_t args_ptr; +{ +	register XDR *xdrs = &(su_data(xprt)->su_xdrs); + +	xdrs->x_op = XDR_FREE; +	return ((*xdr_args)(xdrs, args_ptr)); +} + +static void +svcudp_destroy(xprt) +	register SVCXPRT *xprt; +{ +	register struct svcudp_data *su = su_data(xprt); + +	xprt_unregister(xprt); +	(void)close(xprt->xp_sock); +	XDR_DESTROY(&(su->su_xdrs)); +	mem_free(rpc_buffer(xprt), su->su_iosz); +	mem_free((caddr_t)su, sizeof(struct svcudp_data)); +	mem_free((caddr_t)xprt, sizeof(SVCXPRT)); +} + + +/***********this could be a separate file*********************/ + +/* + * Fifo cache for udp server + * Copies pointers to reply buffers into fifo cache + * Buffers are sent again if retransmissions are detected. + */ + +#define SPARSENESS 4	/* 75% sparse */ + +#define CACHE_PERROR(msg)	\ +	(void) fprintf(stderr,"%s\n", msg) + +#define ALLOC(type, size)	\ +	(type *) mem_alloc((unsigned) (sizeof(type) * (size))) + +#define BZERO(addr, type, size)	 \ +	bzero((char *) addr, sizeof(type) * (int) (size))  + +/* + * An entry in the cache + */ +typedef struct cache_node *cache_ptr; +struct cache_node { +	/* +	 * Index into cache is xid, proc, vers, prog and address +	 */ +	u_long cache_xid; +	u_long cache_proc; +	u_long cache_vers; +	u_long cache_prog; +	struct sockaddr_in cache_addr; +	/* +	 * The cached reply and length +	 */ +	char * cache_reply; +	u_long cache_replylen; +	/* + 	 * Next node on the list, if there is a collision +	 */ +	cache_ptr cache_next;	 +}; + + + +/* + * The entire cache + */ +struct udp_cache { +	u_long uc_size;		/* size of cache */ +	cache_ptr *uc_entries;	/* hash table of entries in cache */ +	cache_ptr *uc_fifo;	/* fifo list of entries in cache */ +	u_long uc_nextvictim;	/* points to next victim in fifo list */ +	u_long uc_prog;		/* saved program number */ +	u_long uc_vers;		/* saved version number */ +	u_long uc_proc;		/* saved procedure number */ +	struct sockaddr_in uc_addr; /* saved caller's address */ +}; + + +/* + * the hashing function + */ +#define CACHE_LOC(transp, xid)	\ + (xid % (SPARSENESS*((struct udp_cache *) su_data(transp)->su_cache)->uc_size))	 + + +/* + * Enable use of the cache.  + * Note: there is no disable. + */ +svcudp_enablecache(transp, size) +	SVCXPRT *transp; +	u_long size; +{ +	struct svcudp_data *su = su_data(transp); +	struct udp_cache *uc; + +	if (su->su_cache != NULL) { +		CACHE_PERROR("enablecache: cache already enabled"); +		return(0);	 +	} +	uc = ALLOC(struct udp_cache, 1); +	if (uc == NULL) { +		CACHE_PERROR("enablecache: could not allocate cache"); +		return(0); +	} +	uc->uc_size = size; +	uc->uc_nextvictim = 0; +	uc->uc_entries = ALLOC(cache_ptr, size * SPARSENESS); +	if (uc->uc_entries == NULL) { +		CACHE_PERROR("enablecache: could not allocate cache data"); +		return(0); +	} +	BZERO(uc->uc_entries, cache_ptr, size * SPARSENESS); +	uc->uc_fifo = ALLOC(cache_ptr, size); +	if (uc->uc_fifo == NULL) { +		CACHE_PERROR("enablecache: could not allocate cache fifo"); +		return(0); +	} +	BZERO(uc->uc_fifo, cache_ptr, size); +	su->su_cache = (char *) uc; +	return(1); +} + + +/* + * Set an entry in the cache + */ +static void +cache_set(xprt, replylen) +	SVCXPRT *xprt; +	u_long replylen;	 +{ +	register cache_ptr victim;	 +	register cache_ptr *vicp; +	register struct svcudp_data *su = su_data(xprt); +	struct udp_cache *uc = (struct udp_cache *) su->su_cache; +	u_int loc; +	char *newbuf; + +	/* + 	 * Find space for the new entry, either by +	 * reusing an old entry, or by mallocing a new one +	 */ +	victim = uc->uc_fifo[uc->uc_nextvictim]; +	if (victim != NULL) { +		loc = CACHE_LOC(xprt, victim->cache_xid); +		for (vicp = &uc->uc_entries[loc];  +		  *vicp != NULL && *vicp != victim;  +		  vicp = &(*vicp)->cache_next)  +				; +		if (*vicp == NULL) { +			CACHE_PERROR("cache_set: victim not found"); +			return; +		} +		*vicp = victim->cache_next;	/* remote from cache */ +		newbuf = victim->cache_reply; +	} else { +		victim = ALLOC(struct cache_node, 1); +		if (victim == NULL) { +			CACHE_PERROR("cache_set: victim alloc failed"); +			return; +		} +		newbuf = mem_alloc(su->su_iosz); +		if (newbuf == NULL) { +			CACHE_PERROR("cache_set: could not allocate new rpc_buffer"); +			return; +		} +	} + +	/* +	 * Store it away +	 */ +	victim->cache_replylen = replylen; +	victim->cache_reply = rpc_buffer(xprt); +	rpc_buffer(xprt) = newbuf; +	xdrmem_create(&(su->su_xdrs), rpc_buffer(xprt), su->su_iosz, XDR_ENCODE); +	victim->cache_xid = su->su_xid; +	victim->cache_proc = uc->uc_proc; +	victim->cache_vers = uc->uc_vers; +	victim->cache_prog = uc->uc_prog; +	victim->cache_addr = uc->uc_addr; +	loc = CACHE_LOC(xprt, victim->cache_xid); +	victim->cache_next = uc->uc_entries[loc];	 +	uc->uc_entries[loc] = victim; +	uc->uc_fifo[uc->uc_nextvictim++] = victim; +	uc->uc_nextvictim %= uc->uc_size; +} + +/* + * Try to get an entry from the cache + * return 1 if found, 0 if not found + */ +static +cache_get(xprt, msg, replyp, replylenp) +	SVCXPRT *xprt; +	struct rpc_msg *msg; +	char **replyp; +	u_long *replylenp; +{ +	u_int loc; +	register cache_ptr ent; +	register struct svcudp_data *su = su_data(xprt); +	register struct udp_cache *uc = (struct udp_cache *) su->su_cache; + +#	define EQADDR(a1, a2)	(bcmp((char*)&a1, (char*)&a2, sizeof(a1)) == 0) + +	loc = CACHE_LOC(xprt, su->su_xid); +	for (ent = uc->uc_entries[loc]; ent != NULL; ent = ent->cache_next) { +		if (ent->cache_xid == su->su_xid && +		  ent->cache_proc == uc->uc_proc && +		  ent->cache_vers == uc->uc_vers && +		  ent->cache_prog == uc->uc_prog && +		  EQADDR(ent->cache_addr, uc->uc_addr)) { +			*replyp = ent->cache_reply; +			*replylenp = ent->cache_replylen; +			return(1); +		} +	} +	/* +	 * Failed to find entry +	 * Remember a few things so we can do a set later +	 */ +	uc->uc_proc = msg->rm_call.cb_proc; +	uc->uc_vers = msg->rm_call.cb_vers; +	uc->uc_prog = msg->rm_call.cb_prog; +	uc->uc_addr = xprt->xp_raddr; +	return(0); +} + diff --git a/lib/librpc/rpc/types.h b/lib/librpc/rpc/types.h new file mode 100644 index 000000000000..06d22bf8006a --- /dev/null +++ b/lib/librpc/rpc/types.h @@ -0,0 +1,63 @@ +/* @(#)types.h	2.3 88/08/15 4.0 RPCSRC */ +/* + * Sun RPC is a product of Sun Microsystems, Inc. and is provided for + * unrestricted use provided that this legend is included on all tape + * media and as a part of the software program in whole or part.  Users + * may copy or modify Sun RPC without charge, but are not authorized + * to license or distribute it to anyone else except as part of a product or + * program developed by the user. + *  + * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE + * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR + * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. + *  + * Sun RPC is provided with no support and without any obligation on the + * part of Sun Microsystems, Inc. to assist in its use, correction, + * modification or enhancement. + *  + * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE + * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC + * OR ANY PART THEREOF. + *  + * In no event will Sun Microsystems, Inc. be liable for any lost revenue + * or profits or other special, indirect and consequential damages, even if + * Sun has been advised of the possibility of such damages. + *  + * Sun Microsystems, Inc. + * 2550 Garcia Avenue + * Mountain View, California  94043 + */ +/*      @(#)types.h 1.18 87/07/24 SMI      */ + +/* + * Rpc additions to <sys/types.h> + */ +#ifndef __TYPES_RPC_HEADER__ +#define __TYPES_RPC_HEADER__ + +#define	bool_t	int +#define	enum_t	int +#define	FALSE	(0) +#define	TRUE	(1) +#define __dontcare__	-1 +#ifndef NULL +#	define NULL 0 +#endif + +void *malloc(); +#define mem_alloc(bsize)	malloc(bsize) +#define mem_free(ptr, bsize)	free(ptr) + +#ifndef makedev /* ie, we haven't already included it */ +#include <sys/types.h> +#endif +#include <sys/time.h> + +#ifndef INADDR_LOOPBACK +#define       INADDR_LOOPBACK         (u_long)0x7F000001 +#endif +#ifndef MAXHOSTNAMELEN +#define        MAXHOSTNAMELEN  64 +#endif + +#endif /* ndef __TYPES_RPC_HEADER__ */ diff --git a/lib/librpc/rpc/xdr.c b/lib/librpc/rpc/xdr.c new file mode 100644 index 000000000000..6c379c9e1b86 --- /dev/null +++ b/lib/librpc/rpc/xdr.c @@ -0,0 +1,576 @@ +/* @(#)xdr.c	2.1 88/07/29 4.0 RPCSRC */ +/* + * Sun RPC is a product of Sun Microsystems, Inc. and is provided for + * unrestricted use provided that this legend is included on all tape + * media and as a part of the software program in whole or part.  Users + * may copy or modify Sun RPC without charge, but are not authorized + * to license or distribute it to anyone else except as part of a product or + * program developed by the user. + *  + * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE + * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR + * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. + *  + * Sun RPC is provided with no support and without any obligation on the + * part of Sun Microsystems, Inc. to assist in its use, correction, + * modification or enhancement. + *  + * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE + * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC + * OR ANY PART THEREOF. + *  + * In no event will Sun Microsystems, Inc. be liable for any lost revenue + * or profits or other special, indirect and consequential damages, even if + * Sun has been advised of the possibility of such damages. + *  + * Sun Microsystems, Inc. + * 2550 Garcia Avenue + * Mountain View, California  94043 + */ +#if !defined(lint) && defined(SCCSIDS) +static char sccsid[] = "@(#)xdr.c 1.35 87/08/12"; +#endif + +/* + * xdr.c, Generic XDR routines implementation. + * + * Copyright (C) 1986, Sun Microsystems, Inc. + * + * These are the "generic" xdr routines used to serialize and de-serialize + * most common data items.  See xdr.h for more info on the interface to + * xdr. + */ + +#include <stdio.h> + +#include <rpc/types.h> +#include <rpc/xdr.h> + +/* + * constants specific to the xdr "protocol" + */ +#define XDR_FALSE	((long) 0) +#define XDR_TRUE	((long) 1) +#define LASTUNSIGNED	((u_int) 0-1) + +/* + * for unit alignment + */ +static char xdr_zero[BYTES_PER_XDR_UNIT] = { 0, 0, 0, 0 }; + +/* + * Free a data structure using XDR + * Not a filter, but a convenient utility nonetheless + */ +void +xdr_free(proc, objp) +	xdrproc_t proc; +	char *objp; +{ +	XDR x; +	 +	x.x_op = XDR_FREE; +	(*proc)(&x, objp); +} + +/* + * XDR nothing + */ +bool_t +xdr_void(/* xdrs, addr */) +	/* XDR *xdrs; */ +	/* caddr_t addr; */ +{ + +	return (TRUE); +} + +/* + * XDR integers + */ +bool_t +xdr_int(xdrs, ip) +	XDR *xdrs; +	int *ip; +{ + +#ifdef lint +	(void) (xdr_short(xdrs, (short *)ip)); +	return (xdr_long(xdrs, (long *)ip)); +#else +	if (sizeof (int) == sizeof (long)) { +		return (xdr_long(xdrs, (long *)ip)); +	} else { +		return (xdr_short(xdrs, (short *)ip)); +	} +#endif +} + +/* + * XDR unsigned integers + */ +bool_t +xdr_u_int(xdrs, up) +	XDR *xdrs; +	u_int *up; +{ + +#ifdef lint +	(void) (xdr_short(xdrs, (short *)up)); +	return (xdr_u_long(xdrs, (u_long *)up)); +#else +	if (sizeof (u_int) == sizeof (u_long)) { +		return (xdr_u_long(xdrs, (u_long *)up)); +	} else { +		return (xdr_short(xdrs, (short *)up)); +	} +#endif +} + +/* + * XDR long integers + * same as xdr_u_long - open coded to save a proc call! + */ +bool_t +xdr_long(xdrs, lp) +	register XDR *xdrs; +	long *lp; +{ + +	if (xdrs->x_op == XDR_ENCODE) +		return (XDR_PUTLONG(xdrs, lp)); + +	if (xdrs->x_op == XDR_DECODE) +		return (XDR_GETLONG(xdrs, lp)); + +	if (xdrs->x_op == XDR_FREE) +		return (TRUE); + +	return (FALSE); +} + +/* + * XDR unsigned long integers + * same as xdr_long - open coded to save a proc call! + */ +bool_t +xdr_u_long(xdrs, ulp) +	register XDR *xdrs; +	u_long *ulp; +{ + +	if (xdrs->x_op == XDR_DECODE) +		return (XDR_GETLONG(xdrs, (long *)ulp)); +	if (xdrs->x_op == XDR_ENCODE) +		return (XDR_PUTLONG(xdrs, (long *)ulp)); +	if (xdrs->x_op == XDR_FREE) +		return (TRUE); +	return (FALSE); +} + +/* + * XDR short integers + */ +bool_t +xdr_short(xdrs, sp) +	register XDR *xdrs; +	short *sp; +{ +	long l; + +	switch (xdrs->x_op) { + +	case XDR_ENCODE: +		l = (long) *sp; +		return (XDR_PUTLONG(xdrs, &l)); + +	case XDR_DECODE: +		if (!XDR_GETLONG(xdrs, &l)) { +			return (FALSE); +		} +		*sp = (short) l; +		return (TRUE); + +	case XDR_FREE: +		return (TRUE); +	} +	return (FALSE); +} + +/* + * XDR unsigned short integers + */ +bool_t +xdr_u_short(xdrs, usp) +	register XDR *xdrs; +	u_short *usp; +{ +	u_long l; + +	switch (xdrs->x_op) { + +	case XDR_ENCODE: +		l = (u_long) *usp; +		return (XDR_PUTLONG(xdrs, &l)); + +	case XDR_DECODE: +		if (!XDR_GETLONG(xdrs, &l)) { +			return (FALSE); +		} +		*usp = (u_short) l; +		return (TRUE); + +	case XDR_FREE: +		return (TRUE); +	} +	return (FALSE); +} + + +/* + * XDR a char + */ +bool_t +xdr_char(xdrs, cp) +	XDR *xdrs; +	char *cp; +{ +	int i; + +	i = (*cp); +	if (!xdr_int(xdrs, &i)) { +		return (FALSE); +	} +	*cp = i; +	return (TRUE); +} + +/* + * XDR an unsigned char + */ +bool_t +xdr_u_char(xdrs, cp) +	XDR *xdrs; +	char *cp; +{ +	u_int u; + +	u = (*cp); +	if (!xdr_u_int(xdrs, &u)) { +		return (FALSE); +	} +	*cp = u; +	return (TRUE); +} + +/* + * XDR booleans + */ +bool_t +xdr_bool(xdrs, bp) +	register XDR *xdrs; +	bool_t *bp; +{ +	long lb; + +	switch (xdrs->x_op) { + +	case XDR_ENCODE: +		lb = *bp ? XDR_TRUE : XDR_FALSE; +		return (XDR_PUTLONG(xdrs, &lb)); + +	case XDR_DECODE: +		if (!XDR_GETLONG(xdrs, &lb)) { +			return (FALSE); +		} +		*bp = (lb == XDR_FALSE) ? FALSE : TRUE; +		return (TRUE); + +	case XDR_FREE: +		return (TRUE); +	} +	return (FALSE); +} + +/* + * XDR enumerations + */ +bool_t +xdr_enum(xdrs, ep) +	XDR *xdrs; +	enum_t *ep; +{ +#ifndef lint +	enum sizecheck { SIZEVAL };	/* used to find the size of an enum */ + +	/* +	 * enums are treated as ints +	 */ +	if (sizeof (enum sizecheck) == sizeof (long)) { +		return (xdr_long(xdrs, (long *)ep)); +	} else if (sizeof (enum sizecheck) == sizeof (short)) { +		return (xdr_short(xdrs, (short *)ep)); +	} else { +		return (FALSE); +	} +#else +	(void) (xdr_short(xdrs, (short *)ep)); +	return (xdr_long(xdrs, (long *)ep)); +#endif +} + +/* + * XDR opaque data + * Allows the specification of a fixed size sequence of opaque bytes. + * cp points to the opaque object and cnt gives the byte length. + */ +bool_t +xdr_opaque(xdrs, cp, cnt) +	register XDR *xdrs; +	caddr_t cp; +	register u_int cnt; +{ +	register u_int rndup; +	static crud[BYTES_PER_XDR_UNIT]; + +	/* +	 * if no data we are done +	 */ +	if (cnt == 0) +		return (TRUE); + +	/* +	 * round byte count to full xdr units +	 */ +	rndup = cnt % BYTES_PER_XDR_UNIT; +	if (rndup > 0) +		rndup = BYTES_PER_XDR_UNIT - rndup; + +	if (xdrs->x_op == XDR_DECODE) { +		if (!XDR_GETBYTES(xdrs, cp, cnt)) { +			return (FALSE); +		} +		if (rndup == 0) +			return (TRUE); +		return (XDR_GETBYTES(xdrs, crud, rndup)); +	} + +	if (xdrs->x_op == XDR_ENCODE) { +		if (!XDR_PUTBYTES(xdrs, cp, cnt)) { +			return (FALSE); +		} +		if (rndup == 0) +			return (TRUE); +		return (XDR_PUTBYTES(xdrs, xdr_zero, rndup)); +	} + +	if (xdrs->x_op == XDR_FREE) { +		return (TRUE); +	} + +	return (FALSE); +} + +/* + * XDR counted bytes + * *cpp is a pointer to the bytes, *sizep is the count. + * If *cpp is NULL maxsize bytes are allocated + */ +bool_t +xdr_bytes(xdrs, cpp, sizep, maxsize) +	register XDR *xdrs; +	char **cpp; +	register u_int *sizep; +	u_int maxsize; +{ +	register char *sp = *cpp;  /* sp is the actual string pointer */ +	register u_int nodesize; + +	/* +	 * first deal with the length since xdr bytes are counted +	 */ +	if (! xdr_u_int(xdrs, sizep)) { +		return (FALSE); +	} +	nodesize = *sizep; +	if ((nodesize > maxsize) && (xdrs->x_op != XDR_FREE)) { +		return (FALSE); +	} + +	/* +	 * now deal with the actual bytes +	 */ +	switch (xdrs->x_op) { + +	case XDR_DECODE: +		if (nodesize == 0) { +			return (TRUE); +		} +		if (sp == NULL) { +			*cpp = sp = (char *)mem_alloc(nodesize); +		} +		if (sp == NULL) { +			(void) fprintf(stderr, "xdr_bytes: out of memory\n"); +			return (FALSE); +		} +		/* fall into ... */ + +	case XDR_ENCODE: +		return (xdr_opaque(xdrs, sp, nodesize)); + +	case XDR_FREE: +		if (sp != NULL) { +			mem_free(sp, nodesize); +			*cpp = NULL; +		} +		return (TRUE); +	} +	return (FALSE); +} + +/* + * Implemented here due to commonality of the object. + */ +bool_t +xdr_netobj(xdrs, np) +	XDR *xdrs; +	struct netobj *np; +{ + +	return (xdr_bytes(xdrs, &np->n_bytes, &np->n_len, MAX_NETOBJ_SZ)); +} + +/* + * XDR a descriminated union + * Support routine for discriminated unions. + * You create an array of xdrdiscrim structures, terminated with + * an entry with a null procedure pointer.  The routine gets + * the discriminant value and then searches the array of xdrdiscrims + * looking for that value.  It calls the procedure given in the xdrdiscrim + * to handle the discriminant.  If there is no specific routine a default + * routine may be called. + * If there is no specific or default routine an error is returned. + */ +bool_t +xdr_union(xdrs, dscmp, unp, choices, dfault) +	register XDR *xdrs; +	enum_t *dscmp;		/* enum to decide which arm to work on */ +	char *unp;		/* the union itself */ +	struct xdr_discrim *choices;	/* [value, xdr proc] for each arm */ +	xdrproc_t dfault;	/* default xdr routine */ +{ +	register enum_t dscm; + +	/* +	 * we deal with the discriminator;  it's an enum +	 */ +	if (! xdr_enum(xdrs, dscmp)) { +		return (FALSE); +	} +	dscm = *dscmp; + +	/* +	 * search choices for a value that matches the discriminator. +	 * if we find one, execute the xdr routine for that value. +	 */ +	for (; choices->proc != NULL_xdrproc_t; choices++) { +		if (choices->value == dscm) +			return ((*(choices->proc))(xdrs, unp, LASTUNSIGNED)); +	} + +	/* +	 * no match - execute the default xdr routine if there is one +	 */ +	return ((dfault == NULL_xdrproc_t) ? FALSE : +	    (*dfault)(xdrs, unp, LASTUNSIGNED)); +} + + +/* + * Non-portable xdr primitives. + * Care should be taken when moving these routines to new architectures. + */ + + +/* + * XDR null terminated ASCII strings + * xdr_string deals with "C strings" - arrays of bytes that are + * terminated by a NULL character.  The parameter cpp references a + * pointer to storage; If the pointer is null, then the necessary + * storage is allocated.  The last parameter is the max allowed length + * of the string as specified by a protocol. + */ +bool_t +xdr_string(xdrs, cpp, maxsize) +	register XDR *xdrs; +	char **cpp; +	u_int maxsize; +{ +	register char *sp = *cpp;  /* sp is the actual string pointer */ +	u_int size; +	u_int nodesize; + +	/* +	 * first deal with the length since xdr strings are counted-strings +	 */ +	switch (xdrs->x_op) { +	case XDR_FREE: +		if (sp == NULL) { +			return(TRUE);	/* already free */ +		} +		/* fall through... */ +	case XDR_ENCODE: +		size = strlen(sp); +		break; +	} +	if (! xdr_u_int(xdrs, &size)) { +		return (FALSE); +	} +	if (size > maxsize) { +		return (FALSE); +	} +	nodesize = size + 1; + +	/* +	 * now deal with the actual bytes +	 */ +	switch (xdrs->x_op) { + +	case XDR_DECODE: +		if (nodesize == 0) { +			return (TRUE); +		} +		if (sp == NULL) +			*cpp = sp = (char *)mem_alloc(nodesize); +		if (sp == NULL) { +			(void) fprintf(stderr, "xdr_string: out of memory\n"); +			return (FALSE); +		} +		sp[size] = 0; +		/* fall into ... */ + +	case XDR_ENCODE: +		return (xdr_opaque(xdrs, sp, size)); + +	case XDR_FREE: +		mem_free(sp, nodesize); +		*cpp = NULL; +		return (TRUE); +	} +	return (FALSE); +} + +/*  + * Wrapper for xdr_string that can be called directly from  + * routines like clnt_call + */ +bool_t +xdr_wrapstring(xdrs, cpp) +	XDR *xdrs; +	char **cpp; +{ +	if (xdr_string(xdrs, cpp, LASTUNSIGNED)) { +		return (TRUE); +	} +	return (FALSE); +} diff --git a/lib/librpc/rpc/xdr.h b/lib/librpc/rpc/xdr.h new file mode 100644 index 000000000000..6cd3e6fe0397 --- /dev/null +++ b/lib/librpc/rpc/xdr.h @@ -0,0 +1,270 @@ +/* @(#)xdr.h	2.2 88/07/29 4.0 RPCSRC */ +/* + * Sun RPC is a product of Sun Microsystems, Inc. and is provided for + * unrestricted use provided that this legend is included on all tape + * media and as a part of the software program in whole or part.  Users + * may copy or modify Sun RPC without charge, but are not authorized + * to license or distribute it to anyone else except as part of a product or + * program developed by the user. + *  + * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE + * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR + * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. + *  + * Sun RPC is provided with no support and without any obligation on the + * part of Sun Microsystems, Inc. to assist in its use, correction, + * modification or enhancement. + *  + * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE + * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC + * OR ANY PART THEREOF. + *  + * In no event will Sun Microsystems, Inc. be liable for any lost revenue + * or profits or other special, indirect and consequential damages, even if + * Sun has been advised of the possibility of such damages. + *  + * Sun Microsystems, Inc. + * 2550 Garcia Avenue + * Mountain View, California  94043 + */ +/*      @(#)xdr.h 1.19 87/04/22 SMI      */ + +/* + * xdr.h, External Data Representation Serialization Routines. + * + * Copyright (C) 1984, Sun Microsystems, Inc. + */ + +#ifndef __XDR_HEADER__ +#define __XDR_HEADER__ + +/* + * XDR provides a conventional way for converting between C data + * types and an external bit-string representation.  Library supplied + * routines provide for the conversion on built-in C data types.  These + * routines and utility routines defined here are used to help implement + * a type encode/decode routine for each user-defined type. + * + * Each data type provides a single procedure which takes two arguments: + * + *	bool_t + *	xdrproc(xdrs, argresp) + *		XDR *xdrs; + *		<type> *argresp; + * + * xdrs is an instance of a XDR handle, to which or from which the data + * type is to be converted.  argresp is a pointer to the structure to be + * converted.  The XDR handle contains an operation field which indicates + * which of the operations (ENCODE, DECODE * or FREE) is to be performed. + * + * XDR_DECODE may allocate space if the pointer argresp is null.  This + * data can be freed with the XDR_FREE operation. + * + * We write only one procedure per data type to make it easy + * to keep the encode and decode procedures for a data type consistent. + * In many cases the same code performs all operations on a user defined type, + * because all the hard work is done in the component type routines. + * decode as a series of calls on the nested data types. + */ + +/* + * Xdr operations.  XDR_ENCODE causes the type to be encoded into the + * stream.  XDR_DECODE causes the type to be extracted from the stream. + * XDR_FREE can be used to release the space allocated by an XDR_DECODE + * request. + */ +enum xdr_op { +	XDR_ENCODE=0, +	XDR_DECODE=1, +	XDR_FREE=2 +}; + +/* + * This is the number of bytes per unit of external data. + */ +#define BYTES_PER_XDR_UNIT	(4) +#define RNDUP(x)  ((((x) + BYTES_PER_XDR_UNIT - 1) / BYTES_PER_XDR_UNIT) \ +		    * BYTES_PER_XDR_UNIT) + +/* + * A xdrproc_t exists for each data type which is to be encoded or decoded. + * + * The second argument to the xdrproc_t is a pointer to an opaque pointer. + * The opaque pointer generally points to a structure of the data type + * to be decoded.  If this pointer is 0, then the type routines should + * allocate dynamic storage of the appropriate size and return it. + * bool_t	(*xdrproc_t)(XDR *, caddr_t *); + */ +typedef	bool_t (*xdrproc_t)(); + +/* + * The XDR handle. + * Contains operation which is being applied to the stream, + * an operations vector for the paticular implementation (e.g. see xdr_mem.c), + * and two private fields for the use of the particular impelementation. + */ +typedef struct { +	enum xdr_op	x_op;		/* operation; fast additional param */ +	struct xdr_ops { +		bool_t	(*x_getlong)();	/* get a long from underlying stream */ +		bool_t	(*x_putlong)();	/* put a long to " */ +		bool_t	(*x_getbytes)();/* get some bytes from " */ +		bool_t	(*x_putbytes)();/* put some bytes to " */ +		u_int	(*x_getpostn)();/* returns bytes off from beginning */ +		bool_t  (*x_setpostn)();/* lets you reposition the stream */ +		long *	(*x_inline)();	/* buf quick ptr to buffered data */ +		void	(*x_destroy)();	/* free privates of this xdr_stream */ +	} *x_ops; +	caddr_t 	x_public;	/* users' data */ +	caddr_t		x_private;	/* pointer to private data */ +	caddr_t 	x_base;		/* private used for position info */ +	int		x_handy;	/* extra private word */ +} XDR; + +/* + * Operations defined on a XDR handle + * + * XDR		*xdrs; + * long		*longp; + * caddr_t	 addr; + * u_int	 len; + * u_int	 pos; + */ +#define XDR_GETLONG(xdrs, longp)			\ +	(*(xdrs)->x_ops->x_getlong)(xdrs, longp) +#define xdr_getlong(xdrs, longp)			\ +	(*(xdrs)->x_ops->x_getlong)(xdrs, longp) + +#define XDR_PUTLONG(xdrs, longp)			\ +	(*(xdrs)->x_ops->x_putlong)(xdrs, longp) +#define xdr_putlong(xdrs, longp)			\ +	(*(xdrs)->x_ops->x_putlong)(xdrs, longp) + +#define XDR_GETBYTES(xdrs, addr, len)			\ +	(*(xdrs)->x_ops->x_getbytes)(xdrs, addr, len) +#define xdr_getbytes(xdrs, addr, len)			\ +	(*(xdrs)->x_ops->x_getbytes)(xdrs, addr, len) + +#define XDR_PUTBYTES(xdrs, addr, len)			\ +	(*(xdrs)->x_ops->x_putbytes)(xdrs, addr, len) +#define xdr_putbytes(xdrs, addr, len)			\ +	(*(xdrs)->x_ops->x_putbytes)(xdrs, addr, len) + +#define XDR_GETPOS(xdrs)				\ +	(*(xdrs)->x_ops->x_getpostn)(xdrs) +#define xdr_getpos(xdrs)				\ +	(*(xdrs)->x_ops->x_getpostn)(xdrs) + +#define XDR_SETPOS(xdrs, pos)				\ +	(*(xdrs)->x_ops->x_setpostn)(xdrs, pos) +#define xdr_setpos(xdrs, pos)				\ +	(*(xdrs)->x_ops->x_setpostn)(xdrs, pos) + +#define	XDR_INLINE(xdrs, len)				\ +	(*(xdrs)->x_ops->x_inline)(xdrs, len) +#define	xdr_inline(xdrs, len)				\ +	(*(xdrs)->x_ops->x_inline)(xdrs, len) + +#define	XDR_DESTROY(xdrs)				\ +	if ((xdrs)->x_ops->x_destroy) 			\ +		(*(xdrs)->x_ops->x_destroy)(xdrs) +#define	xdr_destroy(xdrs)				\ +	if ((xdrs)->x_ops->x_destroy) 			\ +		(*(xdrs)->x_ops->x_destroy)(xdrs) + +/* + * Support struct for discriminated unions. + * You create an array of xdrdiscrim structures, terminated with + * a entry with a null procedure pointer.  The xdr_union routine gets + * the discriminant value and then searches the array of structures + * for a matching value.  If a match is found the associated xdr routine + * is called to handle that part of the union.  If there is + * no match, then a default routine may be called. + * If there is no match and no default routine it is an error. + */ +#define NULL_xdrproc_t ((xdrproc_t)0) +struct xdr_discrim { +	int	value; +	xdrproc_t proc; +}; + +/* + * In-line routines for fast encode/decode of primitve data types. + * Caveat emptor: these use single memory cycles to get the + * data from the underlying buffer, and will fail to operate + * properly if the data is not aligned.  The standard way to use these + * is to say: + *	if ((buf = XDR_INLINE(xdrs, count)) == NULL) + *		return (FALSE); + *	<<< macro calls >>> + * where ``count'' is the number of bytes of data occupied + * by the primitive data types. + * + * N.B. and frozen for all time: each data type here uses 4 bytes + * of external representation. + */ +#define IXDR_GET_LONG(buf)		((long)ntohl((u_long)*(buf)++)) +#define IXDR_PUT_LONG(buf, v)		(*(buf)++ = (long)htonl((u_long)v)) + +#define IXDR_GET_BOOL(buf)		((bool_t)IXDR_GET_LONG(buf)) +#define IXDR_GET_ENUM(buf, t)		((t)IXDR_GET_LONG(buf)) +#define IXDR_GET_U_LONG(buf)		((u_long)IXDR_GET_LONG(buf)) +#define IXDR_GET_SHORT(buf)		((short)IXDR_GET_LONG(buf)) +#define IXDR_GET_U_SHORT(buf)		((u_short)IXDR_GET_LONG(buf)) + +#define IXDR_PUT_BOOL(buf, v)		IXDR_PUT_LONG((buf), ((long)(v))) +#define IXDR_PUT_ENUM(buf, v)		IXDR_PUT_LONG((buf), ((long)(v))) +#define IXDR_PUT_U_LONG(buf, v)		IXDR_PUT_LONG((buf), ((long)(v))) +#define IXDR_PUT_SHORT(buf, v)		IXDR_PUT_LONG((buf), ((long)(v))) +#define IXDR_PUT_U_SHORT(buf, v)	IXDR_PUT_LONG((buf), ((long)(v))) + +/* + * These are the "generic" xdr routines. + */ +extern bool_t	xdr_void(); +extern bool_t	xdr_int(); +extern bool_t	xdr_u_int(); +extern bool_t	xdr_long(); +extern bool_t	xdr_u_long(); +extern bool_t	xdr_short(); +extern bool_t	xdr_u_short(); +extern bool_t	xdr_bool(); +extern bool_t	xdr_enum(); +extern bool_t	xdr_array(); +extern bool_t	xdr_bytes(); +extern bool_t	xdr_opaque(); +extern bool_t	xdr_string(); +extern bool_t	xdr_union(); +extern bool_t	xdr_char(); +extern bool_t	xdr_u_char(); +extern bool_t	xdr_vector(); +extern bool_t	xdr_float(); +extern bool_t	xdr_double(); +extern bool_t	xdr_reference(); +extern bool_t	xdr_pointer(); +extern bool_t	xdr_wrapstring(); + +/* + * Common opaque bytes objects used by many rpc protocols; + * declared here due to commonality. + */ +#define MAX_NETOBJ_SZ 1024  +struct netobj { +	u_int	n_len; +	char	*n_bytes; +}; +typedef struct netobj netobj; +extern bool_t   xdr_netobj(); + +/* + * These are the public routines for the various implementations of + * xdr streams. + */ +extern void   xdrmem_create();		/* XDR using memory buffers */ +extern void   xdrstdio_create();	/* XDR using stdio library */ +extern void   xdrrec_create();		/* XDR pseudo records for tcp */ +extern bool_t xdrrec_endofrecord();	/* make end of xdr record */ +extern bool_t xdrrec_skiprecord();	/* move to beginning of next record */ +extern bool_t xdrrec_eof();		/* true if no more input */ + +#endif !__XDR_HEADER__ diff --git a/lib/librpc/rpc/xdr_array.c b/lib/librpc/rpc/xdr_array.c new file mode 100644 index 000000000000..7c2831ccd229 --- /dev/null +++ b/lib/librpc/rpc/xdr_array.c @@ -0,0 +1,153 @@ +/* @(#)xdr_array.c	2.1 88/07/29 4.0 RPCSRC */ +/* + * Sun RPC is a product of Sun Microsystems, Inc. and is provided for + * unrestricted use provided that this legend is included on all tape + * media and as a part of the software program in whole or part.  Users + * may copy or modify Sun RPC without charge, but are not authorized + * to license or distribute it to anyone else except as part of a product or + * program developed by the user. + *  + * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE + * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR + * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. + *  + * Sun RPC is provided with no support and without any obligation on the + * part of Sun Microsystems, Inc. to assist in its use, correction, + * modification or enhancement. + *  + * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE + * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC + * OR ANY PART THEREOF. + *  + * In no event will Sun Microsystems, Inc. be liable for any lost revenue + * or profits or other special, indirect and consequential damages, even if + * Sun has been advised of the possibility of such damages. + *  + * Sun Microsystems, Inc. + * 2550 Garcia Avenue + * Mountain View, California  94043 + */ +#if !defined(lint) && defined(SCCSIDS) +static char sccsid[] = "@(#)xdr_array.c 1.10 87/08/11 Copyr 1984 Sun Micro"; +#endif + +/* + * xdr_array.c, Generic XDR routines impelmentation. + * + * Copyright (C) 1984, Sun Microsystems, Inc. + * + * These are the "non-trivial" xdr primitives used to serialize and de-serialize + * arrays.  See xdr.h for more info on the interface to xdr. + */ + +#include <stdio.h> + +#include <rpc/types.h> +#include <rpc/xdr.h> + +#define LASTUNSIGNED	((u_int)0-1) + + +/* + * XDR an array of arbitrary elements + * *addrp is a pointer to the array, *sizep is the number of elements. + * If addrp is NULL (*sizep * elsize) bytes are allocated. + * elsize is the size (in bytes) of each element, and elproc is the + * xdr procedure to call to handle each element of the array. + */ +bool_t +xdr_array(xdrs, addrp, sizep, maxsize, elsize, elproc) +	register XDR *xdrs; +	caddr_t *addrp;		/* array pointer */ +	u_int *sizep;		/* number of elements */ +	u_int maxsize;		/* max numberof elements */ +	u_int elsize;		/* size in bytes of each element */ +	xdrproc_t elproc;	/* xdr routine to handle each element */ +{ +	register u_int i; +	register caddr_t target = *addrp; +	register u_int c;  /* the actual element count */ +	register bool_t stat = TRUE; +	register u_int nodesize; + +	/* like strings, arrays are really counted arrays */ +	if (! xdr_u_int(xdrs, sizep)) { +		return (FALSE); +	} +	c = *sizep; +	if ((c > maxsize) && (xdrs->x_op != XDR_FREE)) { +		return (FALSE); +	} +	nodesize = c * elsize; + +	/* +	 * if we are deserializing, we may need to allocate an array. +	 * We also save time by checking for a null array if we are freeing. +	 */ +	if (target == NULL) +		switch (xdrs->x_op) { +		case XDR_DECODE: +			if (c == 0) +				return (TRUE); +			*addrp = target = mem_alloc(nodesize); +			if (target == NULL) { +				(void) fprintf(stderr,  +					"xdr_array: out of memory\n"); +				return (FALSE); +			} +			bzero(target, nodesize); +			break; + +		case XDR_FREE: +			return (TRUE); +	} +	 +	/* +	 * now we xdr each element of array +	 */ +	for (i = 0; (i < c) && stat; i++) { +		stat = (*elproc)(xdrs, target, LASTUNSIGNED); +		target += elsize; +	} + +	/* +	 * the array may need freeing +	 */ +	if (xdrs->x_op == XDR_FREE) { +		mem_free(*addrp, nodesize); +		*addrp = NULL; +	} +	return (stat); +} + +/* + * xdr_vector(): + * + * XDR a fixed length array. Unlike variable-length arrays, + * the storage of fixed length arrays is static and unfreeable. + * > basep: base of the array + * > size: size of the array + * > elemsize: size of each element + * > xdr_elem: routine to XDR each element + */ +bool_t +xdr_vector(xdrs, basep, nelem, elemsize, xdr_elem) +	register XDR *xdrs; +	register char *basep; +	register u_int nelem; +	register u_int elemsize; +	register xdrproc_t xdr_elem;	 +{ +	register u_int i; +	register char *elptr; + +	elptr = basep; +	for (i = 0; i < nelem; i++) { +		if (! (*xdr_elem)(xdrs, elptr, LASTUNSIGNED)) { +			return(FALSE); +		} +		elptr += elemsize; +	} +	return(TRUE);	 +} + diff --git a/lib/librpc/rpc/xdr_float.c b/lib/librpc/rpc/xdr_float.c new file mode 100644 index 000000000000..4b5b697bcf30 --- /dev/null +++ b/lib/librpc/rpc/xdr_float.c @@ -0,0 +1,267 @@ +/* @(#)xdr_float.c	2.1 88/07/29 4.0 RPCSRC */ +/* + * Sun RPC is a product of Sun Microsystems, Inc. and is provided for + * unrestricted use provided that this legend is included on all tape + * media and as a part of the software program in whole or part.  Users + * may copy or modify Sun RPC without charge, but are not authorized + * to license or distribute it to anyone else except as part of a product or + * program developed by the user. + *  + * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE + * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR + * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. + *  + * Sun RPC is provided with no support and without any obligation on the + * part of Sun Microsystems, Inc. to assist in its use, correction, + * modification or enhancement. + *  + * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE + * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC + * OR ANY PART THEREOF. + *  + * In no event will Sun Microsystems, Inc. be liable for any lost revenue + * or profits or other special, indirect and consequential damages, even if + * Sun has been advised of the possibility of such damages. + *  + * Sun Microsystems, Inc. + * 2550 Garcia Avenue + * Mountain View, California  94043 + */ +#if !defined(lint) && defined(SCCSIDS) +static char sccsid[] = "@(#)xdr_float.c 1.12 87/08/11 Copyr 1984 Sun Micro"; +#endif + +/* + * xdr_float.c, Generic XDR routines impelmentation. + * + * Copyright (C) 1984, Sun Microsystems, Inc. + * + * These are the "floating point" xdr routines used to (de)serialize + * most common data items.  See xdr.h for more info on the interface to + * xdr. + */ + +#include <stdio.h> + +#include <rpc/types.h> +#include <rpc/xdr.h> + +/* + * NB: Not portable. + * This routine works on Suns (Sky / 68000's) and Vaxen. + */ + +#ifdef vax + +/* What IEEE single precision floating point looks like on a Vax */ +struct	ieee_single { +	unsigned int	mantissa: 23; +	unsigned int	exp     : 8; +	unsigned int	sign    : 1; +}; + +/* Vax single precision floating point */ +struct	vax_single { +	unsigned int	mantissa1 : 7; +	unsigned int	exp       : 8; +	unsigned int	sign      : 1; +	unsigned int	mantissa2 : 16; +}; + +#define VAX_SNG_BIAS	0x81 +#define IEEE_SNG_BIAS	0x7f + +static struct sgl_limits { +	struct vax_single s; +	struct ieee_single ieee; +} sgl_limits[2] = { +	{{ 0x7f, 0xff, 0x0, 0xffff },	/* Max Vax */ +	{ 0x0, 0xff, 0x0 }},		/* Max IEEE */ +	{{ 0x0, 0x0, 0x0, 0x0 },	/* Min Vax */ +	{ 0x0, 0x0, 0x0 }}		/* Min IEEE */ +}; +#endif /* vax */ + +bool_t +xdr_float(xdrs, fp) +	register XDR *xdrs; +	register float *fp; +{ +#if !defined(mc68000) && !defined(sparc) +	struct ieee_single is; +	struct vax_single vs, *vsp; +	struct sgl_limits *lim; +	int i; +#endif +	switch (xdrs->x_op) { + +	case XDR_ENCODE: +#if defined(mc68000) || defined(sparc) +		return (XDR_PUTLONG(xdrs, (long *)fp)); +#else +		vs = *((struct vax_single *)fp); +		for (i = 0, lim = sgl_limits; +			i < sizeof(sgl_limits)/sizeof(struct sgl_limits); +			i++, lim++) { +			if ((vs.mantissa2 == lim->s.mantissa2) && +				(vs.exp == lim->s.exp) && +				(vs.mantissa1 == lim->s.mantissa1)) { +				is = lim->ieee; +				goto shipit; +			} +		} +		is.exp = vs.exp - VAX_SNG_BIAS + IEEE_SNG_BIAS; +		is.mantissa = (vs.mantissa1 << 16) | vs.mantissa2; +	shipit: +		is.sign = vs.sign; +		return (XDR_PUTLONG(xdrs, (long *)&is)); +#endif + +	case XDR_DECODE: +#if defined(mc68000) || defined(sparc) +		return (XDR_GETLONG(xdrs, (long *)fp)); +#else +		vsp = (struct vax_single *)fp; +		if (!XDR_GETLONG(xdrs, (long *)&is)) +			return (FALSE); +		for (i = 0, lim = sgl_limits; +			i < sizeof(sgl_limits)/sizeof(struct sgl_limits); +			i++, lim++) { +			if ((is.exp == lim->ieee.exp) && +				(is.mantissa == lim->ieee.mantissa)) { +				*vsp = lim->s; +				goto doneit; +			} +		} +		vsp->exp = is.exp - IEEE_SNG_BIAS + VAX_SNG_BIAS; +		vsp->mantissa2 = is.mantissa; +		vsp->mantissa1 = (is.mantissa >> 16); +	doneit: +		vsp->sign = is.sign; +		return (TRUE); +#endif + +	case XDR_FREE: +		return (TRUE); +	} +	return (FALSE); +} + +/* + * This routine works on Suns (Sky / 68000's) and Vaxen. + */ + +#ifdef vax +/* What IEEE double precision floating point looks like on a Vax */ +struct	ieee_double { +	unsigned int	mantissa1 : 20; +	unsigned int	exp       : 11; +	unsigned int	sign      : 1; +	unsigned int	mantissa2 : 32; +}; + +/* Vax double precision floating point */ +struct  vax_double { +	unsigned int	mantissa1 : 7; +	unsigned int	exp       : 8; +	unsigned int	sign      : 1; +	unsigned int	mantissa2 : 16; +	unsigned int	mantissa3 : 16; +	unsigned int	mantissa4 : 16; +}; + +#define VAX_DBL_BIAS	0x81 +#define IEEE_DBL_BIAS	0x3ff +#define MASK(nbits)	((1 << nbits) - 1) + +static struct dbl_limits { +	struct	vax_double d; +	struct	ieee_double ieee; +} dbl_limits[2] = { +	{{ 0x7f, 0xff, 0x0, 0xffff, 0xffff, 0xffff },	/* Max Vax */ +	{ 0x0, 0x7ff, 0x0, 0x0 }},			/* Max IEEE */ +	{{ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0},		/* Min Vax */ +	{ 0x0, 0x0, 0x0, 0x0 }}				/* Min IEEE */ +}; + +#endif /* vax */ + + +bool_t +xdr_double(xdrs, dp) +	register XDR *xdrs; +	double *dp; +{ +	register long *lp; +#if !defined(mc68000) && !defined(sparc) +	struct	ieee_double id; +	struct	vax_double vd; +	register struct dbl_limits *lim; +	int i; +#endif + +	switch (xdrs->x_op) { + +	case XDR_ENCODE: +#if defined(mc68000) || defined(sparc) +		lp = (long *)dp; +#else +		vd = *((struct vax_double *)dp); +		for (i = 0, lim = dbl_limits; +			i < sizeof(dbl_limits)/sizeof(struct dbl_limits); +			i++, lim++) { +			if ((vd.mantissa4 == lim->d.mantissa4) && +				(vd.mantissa3 == lim->d.mantissa3) && +				(vd.mantissa2 == lim->d.mantissa2) && +				(vd.mantissa1 == lim->d.mantissa1) && +				(vd.exp == lim->d.exp)) { +				id = lim->ieee; +				goto shipit; +			} +		} +		id.exp = vd.exp - VAX_DBL_BIAS + IEEE_DBL_BIAS; +		id.mantissa1 = (vd.mantissa1 << 13) | (vd.mantissa2 >> 3); +		id.mantissa2 = ((vd.mantissa2 & MASK(3)) << 29) | +				(vd.mantissa3 << 13) | +				((vd.mantissa4 >> 3) & MASK(13)); +	shipit: +		id.sign = vd.sign; +		lp = (long *)&id; +#endif +		return (XDR_PUTLONG(xdrs, lp++) && XDR_PUTLONG(xdrs, lp)); + +	case XDR_DECODE: +#if defined(mc68000) || defined(sparc) +		lp = (long *)dp; +		return (XDR_GETLONG(xdrs, lp++) && XDR_GETLONG(xdrs, lp)); +#else +		lp = (long *)&id; +		if (!XDR_GETLONG(xdrs, lp++) || !XDR_GETLONG(xdrs, lp)) +			return (FALSE); +		for (i = 0, lim = dbl_limits; +			i < sizeof(dbl_limits)/sizeof(struct dbl_limits); +			i++, lim++) { +			if ((id.mantissa2 == lim->ieee.mantissa2) && +				(id.mantissa1 == lim->ieee.mantissa1) && +				(id.exp == lim->ieee.exp)) { +				vd = lim->d; +				goto doneit; +			} +		} +		vd.exp = id.exp - IEEE_DBL_BIAS + VAX_DBL_BIAS; +		vd.mantissa1 = (id.mantissa1 >> 13); +		vd.mantissa2 = ((id.mantissa1 & MASK(13)) << 3) | +				(id.mantissa2 >> 29); +		vd.mantissa3 = (id.mantissa2 >> 13); +		vd.mantissa4 = (id.mantissa2 << 3); +	doneit: +		vd.sign = id.sign; +		*dp = *((double *)&vd); +		return (TRUE); +#endif + +	case XDR_FREE: +		return (TRUE); +	} +	return (FALSE); +} diff --git a/lib/librpc/rpc/xdr_mem.c b/lib/librpc/rpc/xdr_mem.c new file mode 100644 index 000000000000..558d36922703 --- /dev/null +++ b/lib/librpc/rpc/xdr_mem.c @@ -0,0 +1,184 @@ +/* @(#)xdr_mem.c	2.1 88/07/29 4.0 RPCSRC */ +/* + * Sun RPC is a product of Sun Microsystems, Inc. and is provided for + * unrestricted use provided that this legend is included on all tape + * media and as a part of the software program in whole or part.  Users + * may copy or modify Sun RPC without charge, but are not authorized + * to license or distribute it to anyone else except as part of a product or + * program developed by the user. + *  + * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE + * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR + * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. + *  + * Sun RPC is provided with no support and without any obligation on the + * part of Sun Microsystems, Inc. to assist in its use, correction, + * modification or enhancement. + *  + * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE + * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC + * OR ANY PART THEREOF. + *  + * In no event will Sun Microsystems, Inc. be liable for any lost revenue + * or profits or other special, indirect and consequential damages, even if + * Sun has been advised of the possibility of such damages. + *  + * Sun Microsystems, Inc. + * 2550 Garcia Avenue + * Mountain View, California  94043 + */ +#if !defined(lint) && defined(SCCSIDS) +static char sccsid[] = "@(#)xdr_mem.c 1.19 87/08/11 Copyr 1984 Sun Micro"; +#endif + +/* + * xdr_mem.h, XDR implementation using memory buffers. + * + * Copyright (C) 1984, Sun Microsystems, Inc. + * + * If you have some data to be interpreted as external data representation + * or to be converted to external data representation in a memory buffer, + * then this is the package for you. + * + */ + + +#include <rpc/types.h> +#include <rpc/xdr.h> +#include <netinet/in.h> + +static bool_t	xdrmem_getlong(); +static bool_t	xdrmem_putlong(); +static bool_t	xdrmem_getbytes(); +static bool_t	xdrmem_putbytes(); +static u_int	xdrmem_getpos(); +static bool_t	xdrmem_setpos(); +static long *	xdrmem_inline(); +static void	xdrmem_destroy(); + +static struct	xdr_ops xdrmem_ops = { +	xdrmem_getlong, +	xdrmem_putlong, +	xdrmem_getbytes, +	xdrmem_putbytes, +	xdrmem_getpos, +	xdrmem_setpos, +	xdrmem_inline, +	xdrmem_destroy +}; + +/* + * The procedure xdrmem_create initializes a stream descriptor for a + * memory buffer.   + */ +void +xdrmem_create(xdrs, addr, size, op) +	register XDR *xdrs; +	caddr_t addr; +	u_int size; +	enum xdr_op op; +{ + +	xdrs->x_op = op; +	xdrs->x_ops = &xdrmem_ops; +	xdrs->x_private = xdrs->x_base = addr; +	xdrs->x_handy = size; +} + +static void +xdrmem_destroy(/*xdrs*/) +	/*XDR *xdrs;*/ +{ +} + +static bool_t +xdrmem_getlong(xdrs, lp) +	register XDR *xdrs; +	long *lp; +{ + +	if ((xdrs->x_handy -= sizeof(long)) < 0) +		return (FALSE); +	*lp = (long)ntohl((u_long)(*((long *)(xdrs->x_private)))); +	xdrs->x_private += sizeof(long); +	return (TRUE); +} + +static bool_t +xdrmem_putlong(xdrs, lp) +	register XDR *xdrs; +	long *lp; +{ + +	if ((xdrs->x_handy -= sizeof(long)) < 0) +		return (FALSE); +	*(long *)xdrs->x_private = (long)htonl((u_long)(*lp)); +	xdrs->x_private += sizeof(long); +	return (TRUE); +} + +static bool_t +xdrmem_getbytes(xdrs, addr, len) +	register XDR *xdrs; +	caddr_t addr; +	register u_int len; +{ + +	if ((xdrs->x_handy -= len) < 0) +		return (FALSE); +	bcopy(xdrs->x_private, addr, len); +	xdrs->x_private += len; +	return (TRUE); +} + +static bool_t +xdrmem_putbytes(xdrs, addr, len) +	register XDR *xdrs; +	caddr_t addr; +	register u_int len; +{ + +	if ((xdrs->x_handy -= len) < 0) +		return (FALSE); +	bcopy(addr, xdrs->x_private, len); +	xdrs->x_private += len; +	return (TRUE); +} + +static u_int +xdrmem_getpos(xdrs) +	register XDR *xdrs; +{ + +	return ((u_int)xdrs->x_private - (u_int)xdrs->x_base); +} + +static bool_t +xdrmem_setpos(xdrs, pos) +	register XDR *xdrs; +	u_int pos; +{ +	register caddr_t newaddr = xdrs->x_base + pos; +	register caddr_t lastaddr = xdrs->x_private + xdrs->x_handy; + +	if ((long)newaddr > (long)lastaddr) +		return (FALSE); +	xdrs->x_private = newaddr; +	xdrs->x_handy = (int)lastaddr - (int)newaddr; +	return (TRUE); +} + +static long * +xdrmem_inline(xdrs, len) +	register XDR *xdrs; +	int len; +{ +	long *buf = 0; + +	if (xdrs->x_handy >= len) { +		xdrs->x_handy -= len; +		buf = (long *) xdrs->x_private; +		xdrs->x_private += len; +	} +	return (buf); +} diff --git a/lib/librpc/rpc/xdr_rec.c b/lib/librpc/rpc/xdr_rec.c new file mode 100644 index 000000000000..6ebea844a684 --- /dev/null +++ b/lib/librpc/rpc/xdr_rec.c @@ -0,0 +1,583 @@ +/* @(#)xdr_rec.c	2.2 88/08/01 4.0 RPCSRC */ +/* + * Sun RPC is a product of Sun Microsystems, Inc. and is provided for + * unrestricted use provided that this legend is included on all tape + * media and as a part of the software program in whole or part.  Users + * may copy or modify Sun RPC without charge, but are not authorized + * to license or distribute it to anyone else except as part of a product or + * program developed by the user. + *  + * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE + * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR + * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. + *  + * Sun RPC is provided with no support and without any obligation on the + * part of Sun Microsystems, Inc. to assist in its use, correction, + * modification or enhancement. + *  + * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE + * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC + * OR ANY PART THEREOF. + *  + * In no event will Sun Microsystems, Inc. be liable for any lost revenue + * or profits or other special, indirect and consequential damages, even if + * Sun has been advised of the possibility of such damages. + *  + * Sun Microsystems, Inc. + * 2550 Garcia Avenue + * Mountain View, California  94043 + */ +#if !defined(lint) && defined(SCCSIDS) +static char sccsid[] = "@(#)xdr_rec.c 1.21 87/08/11 Copyr 1984 Sun Micro"; +#endif + +/* + * xdr_rec.c, Implements TCP/IP based XDR streams with a "record marking" + * layer above tcp (for rpc's use). + * + * Copyright (C) 1984, Sun Microsystems, Inc. + * + * These routines interface XDRSTREAMS to a tcp/ip connection. + * There is a record marking layer between the xdr stream + * and the tcp transport level.  A record is composed on one or more + * record fragments.  A record fragment is a thirty-two bit header followed + * by n bytes of data, where n is contained in the header.  The header + * is represented as a htonl(u_long).  Thegh order bit encodes + * whether or not the fragment is the last fragment of the record + * (1 => fragment is last, 0 => more fragments to follow.  + * The other 31 bits encode the byte length of the fragment. + */ + +#include <stdio.h> +#include <rpc/types.h> +#include <rpc/xdr.h> +#include <netinet/in.h> +#include <unistd.h> + +static u_int	fix_buf_size(); +static bool_t	flush_out(); +static bool_t	get_input_bytes(); +static bool_t	set_input_fragment(); +static bool_t	skip_input_bytes(); + +static bool_t	xdrrec_getlong(); +static bool_t	xdrrec_putlong(); +static bool_t	xdrrec_getbytes(); +static bool_t	xdrrec_putbytes(); +static u_int	xdrrec_getpos(); +static bool_t	xdrrec_setpos(); +static long *	xdrrec_inline(); +static void	xdrrec_destroy(); + +static struct  xdr_ops xdrrec_ops = { +	xdrrec_getlong, +	xdrrec_putlong, +	xdrrec_getbytes, +	xdrrec_putbytes, +	xdrrec_getpos, +	xdrrec_setpos, +	xdrrec_inline, +	xdrrec_destroy +}; + +/* + * A record is composed of one or more record fragments. + * A record fragment is a two-byte header followed by zero to + * 2**32-1 bytes.  The header is treated as a long unsigned and is + * encode/decoded to the network via htonl/ntohl.  The low order 31 bits + * are a byte count of the fragment.  The highest order bit is a boolean: + * 1 => this fragment is the last fragment of the record, + * 0 => this fragment is followed by more fragment(s). + * + * The fragment/record machinery is not general;  it is constructed to + * meet the needs of xdr and rpc based on tcp. + */ + +#define LAST_FRAG ((u_long)(1 << 31)) + +typedef struct rec_strm { +	caddr_t tcp_handle; +	caddr_t the_buffer; +	/* +	 * out-goung bits +	 */ +	int (*writeit)(); +	caddr_t out_base;	/* output buffer (points to frag header) */ +	caddr_t out_finger;	/* next output position */ +	caddr_t out_boundry;	/* data cannot up to this address */ +	u_long *frag_header;	/* beginning of curren fragment */ +	bool_t frag_sent;	/* true if buffer sent in middle of record */ +	/* +	 * in-coming bits +	 */ +	int (*readit)(); +	u_long in_size;	/* fixed size of the input buffer */ +	caddr_t in_base; +	caddr_t in_finger;	/* location of next byte to be had */ +	caddr_t in_boundry;	/* can read up to this location */ +	long fbtbc;		/* fragment bytes to be consumed */ +	bool_t last_frag; +	u_int sendsize; +	u_int recvsize; +} RECSTREAM; + + +/* + * Create an xdr handle for xdrrec + * xdrrec_create fills in xdrs.  Sendsize and recvsize are + * send and recv buffer sizes (0 => use default). + * tcp_handle is an opaque handle that is passed as the first parameter to + * the procedures readit and writeit.  Readit and writeit are read and + * write respectively.   They are like the system + * calls expect that they take an opaque handle rather than an fd. + */ +void +xdrrec_create(xdrs, sendsize, recvsize, tcp_handle, readit, writeit) +	register XDR *xdrs; +	register u_int sendsize; +	register u_int recvsize; +	caddr_t tcp_handle; +	int (*readit)();  /* like read, but pass it a tcp_handle, not sock */ +	int (*writeit)();  /* like write, but pass it a tcp_handle, not sock */ +{ +	register RECSTREAM *rstrm = +		(RECSTREAM *)mem_alloc(sizeof(RECSTREAM)); + +	if (rstrm == NULL) { +		(void)fprintf(stderr, "xdrrec_create: out of memory\n"); +		/*  +		 *  This is bad.  Should rework xdrrec_create to  +		 *  return a handle, and in this case return NULL +		 */ +		return; +	} +	/* +	 * adjust sizes and allocate buffer quad byte aligned +	 */ +	rstrm->sendsize = sendsize = fix_buf_size(sendsize); +	rstrm->recvsize = recvsize = fix_buf_size(recvsize); +	rstrm->the_buffer = mem_alloc(sendsize + recvsize + BYTES_PER_XDR_UNIT); +	if (rstrm->the_buffer == NULL) { +		(void)fprintf(stderr, "xdrrec_create: out of memory\n"); +		return; +	} +	for (rstrm->out_base = rstrm->the_buffer; +		(u_int)rstrm->out_base % BYTES_PER_XDR_UNIT != 0; +		rstrm->out_base++); +	rstrm->in_base = rstrm->out_base + sendsize; +	/* +	 * now the rest ... +	 */ +	xdrs->x_ops = &xdrrec_ops; +	xdrs->x_private = (caddr_t)rstrm; +	rstrm->tcp_handle = tcp_handle; +	rstrm->readit = readit; +	rstrm->writeit = writeit; +	rstrm->out_finger = rstrm->out_boundry = rstrm->out_base; +	rstrm->frag_header = (u_long *)rstrm->out_base; +	rstrm->out_finger += sizeof(u_long); +	rstrm->out_boundry += sendsize; +	rstrm->frag_sent = FALSE; +	rstrm->in_size = recvsize; +	rstrm->in_boundry = rstrm->in_base; +	rstrm->in_finger = (rstrm->in_boundry += recvsize); +	rstrm->fbtbc = 0; +	rstrm->last_frag = TRUE; +} + + +/* + * The reoutines defined below are the xdr ops which will go into the + * xdr handle filled in by xdrrec_create. + */ + +static bool_t +xdrrec_getlong(xdrs, lp) +	XDR *xdrs; +	long *lp; +{ +	register RECSTREAM *rstrm = (RECSTREAM *)(xdrs->x_private); +	register long *buflp = (long *)(rstrm->in_finger); +	long mylong; + +	/* first try the inline, fast case */ +	if ((rstrm->fbtbc >= sizeof(long)) && +		(((int)rstrm->in_boundry - (int)buflp) >= sizeof(long))) { +		*lp = (long)ntohl((u_long)(*buflp)); +		rstrm->fbtbc -= sizeof(long); +		rstrm->in_finger += sizeof(long); +	} else { +		if (! xdrrec_getbytes(xdrs, (caddr_t)&mylong, sizeof(long))) +			return (FALSE); +		*lp = (long)ntohl((u_long)mylong); +	} +	return (TRUE); +} + +static bool_t +xdrrec_putlong(xdrs, lp) +	XDR *xdrs; +	long *lp; +{ +	register RECSTREAM *rstrm = (RECSTREAM *)(xdrs->x_private); +	register long *dest_lp = ((long *)(rstrm->out_finger)); + +	if ((rstrm->out_finger += sizeof(long)) > rstrm->out_boundry) { +		/* +		 * this case should almost never happen so the code is +		 * inefficient +		 */ +		rstrm->out_finger -= sizeof(long); +		rstrm->frag_sent = TRUE; +		if (! flush_out(rstrm, FALSE)) +			return (FALSE); +		dest_lp = ((long *)(rstrm->out_finger)); +		rstrm->out_finger += sizeof(long); +	} +	*dest_lp = (long)htonl((u_long)(*lp)); +	return (TRUE); +} + +static bool_t  /* must manage buffers, fragments, and records */ +xdrrec_getbytes(xdrs, addr, len) +	XDR *xdrs; +	register caddr_t addr; +	register u_int len; +{ +	register RECSTREAM *rstrm = (RECSTREAM *)(xdrs->x_private); +	register int current; + +	while (len > 0) { +		current = rstrm->fbtbc; +		if (current == 0) { +			if (rstrm->last_frag) +				return (FALSE); +			if (! set_input_fragment(rstrm)) +				return (FALSE); +			continue; +		} +		current = (len < current) ? len : current; +		if (! get_input_bytes(rstrm, addr, current)) +			return (FALSE); +		addr += current;  +		rstrm->fbtbc -= current; +		len -= current; +	} +	return (TRUE); +} + +static bool_t +xdrrec_putbytes(xdrs, addr, len) +	XDR *xdrs; +	register caddr_t addr; +	register u_int len; +{ +	register RECSTREAM *rstrm = (RECSTREAM *)(xdrs->x_private); +	register int current; + +	while (len > 0) { +		current = (u_int)rstrm->out_boundry - (u_int)rstrm->out_finger; +		current = (len < current) ? len : current; +		bcopy(addr, rstrm->out_finger, current); +		rstrm->out_finger += current; +		addr += current; +		len -= current; +		if (rstrm->out_finger == rstrm->out_boundry) { +			rstrm->frag_sent = TRUE; +			if (! flush_out(rstrm, FALSE)) +				return (FALSE); +		} +	} +	return (TRUE); +} + +static u_int +xdrrec_getpos(xdrs) +	register XDR *xdrs; +{ +	register RECSTREAM *rstrm = (RECSTREAM *)xdrs->x_private; +	register long pos; + +	pos = lseek((int)rstrm->tcp_handle, (long) 0, 1); +	if (pos != -1) +		switch (xdrs->x_op) { + +		case XDR_ENCODE: +			pos += rstrm->out_finger - rstrm->out_base; +			break; + +		case XDR_DECODE: +			pos -= rstrm->in_boundry - rstrm->in_finger; +			break; + +		default: +			pos = (u_int) -1; +			break; +		} +	return ((u_int) pos); +} + +static bool_t +xdrrec_setpos(xdrs, pos) +	register XDR *xdrs; +	u_int pos; +{ +	register RECSTREAM *rstrm = (RECSTREAM *)xdrs->x_private; +	u_int currpos = xdrrec_getpos(xdrs); +	int delta = currpos - pos; +	caddr_t newpos; + +	if ((int)currpos != -1) +		switch (xdrs->x_op) { + +		case XDR_ENCODE: +			newpos = rstrm->out_finger - delta; +			if ((newpos > (caddr_t)(rstrm->frag_header)) && +				(newpos < rstrm->out_boundry)) { +				rstrm->out_finger = newpos; +				return (TRUE); +			} +			break; + +		case XDR_DECODE: +			newpos = rstrm->in_finger - delta; +			if ((delta < (int)(rstrm->fbtbc)) && +				(newpos <= rstrm->in_boundry) && +				(newpos >= rstrm->in_base)) { +				rstrm->in_finger = newpos; +				rstrm->fbtbc -= delta; +				return (TRUE); +			} +			break; +		} +	return (FALSE); +} + +static long * +xdrrec_inline(xdrs, len) +	register XDR *xdrs; +	int len; +{ +	register RECSTREAM *rstrm = (RECSTREAM *)xdrs->x_private; +	long * buf = NULL; + +	switch (xdrs->x_op) { + +	case XDR_ENCODE: +		if ((rstrm->out_finger + len) <= rstrm->out_boundry) { +			buf = (long *) rstrm->out_finger; +			rstrm->out_finger += len; +		} +		break; + +	case XDR_DECODE: +		if ((len <= rstrm->fbtbc) && +			((rstrm->in_finger + len) <= rstrm->in_boundry)) { +			buf = (long *) rstrm->in_finger; +			rstrm->fbtbc -= len; +			rstrm->in_finger += len; +		} +		break; +	} +	return (buf); +} + +static void +xdrrec_destroy(xdrs) +	register XDR *xdrs; +{ +	register RECSTREAM *rstrm = (RECSTREAM *)xdrs->x_private; + +	mem_free(rstrm->the_buffer, +		rstrm->sendsize + rstrm->recvsize + BYTES_PER_XDR_UNIT); +	mem_free((caddr_t)rstrm, sizeof(RECSTREAM)); +} + + +/* + * Exported routines to manage xdr records + */ + +/* + * Before reading (deserializing from the stream, one should always call + * this procedure to guarantee proper record alignment. + */ +bool_t +xdrrec_skiprecord(xdrs) +	XDR *xdrs; +{ +	register RECSTREAM *rstrm = (RECSTREAM *)(xdrs->x_private); + +	while (rstrm->fbtbc > 0 || (! rstrm->last_frag)) { +		if (! skip_input_bytes(rstrm, rstrm->fbtbc)) +			return (FALSE); +		rstrm->fbtbc = 0; +		if ((! rstrm->last_frag) && (! set_input_fragment(rstrm))) +			return (FALSE); +	} +	rstrm->last_frag = FALSE; +	return (TRUE); +} + +/* + * Look ahead fuction. + * Returns TRUE iff there is no more input in the buffer  + * after consuming the rest of the current record. + */ +bool_t +xdrrec_eof(xdrs) +	XDR *xdrs; +{ +	register RECSTREAM *rstrm = (RECSTREAM *)(xdrs->x_private); + +	while (rstrm->fbtbc > 0 || (! rstrm->last_frag)) { +		if (! skip_input_bytes(rstrm, rstrm->fbtbc)) +			return (TRUE); +		rstrm->fbtbc = 0; +		if ((! rstrm->last_frag) && (! set_input_fragment(rstrm))) +			return (TRUE); +	} +	if (rstrm->in_finger == rstrm->in_boundry) +		return (TRUE); +	return (FALSE); +} + +/* + * The client must tell the package when an end-of-record has occurred. + * The second paraemters tells whether the record should be flushed to the + * (output) tcp stream.  (This let's the package support batched or + * pipelined procedure calls.)  TRUE => immmediate flush to tcp connection. + */ +bool_t +xdrrec_endofrecord(xdrs, sendnow) +	XDR *xdrs; +	bool_t sendnow; +{ +	register RECSTREAM *rstrm = (RECSTREAM *)(xdrs->x_private); +	register u_long len;  /* fragment length */ + +	if (sendnow || rstrm->frag_sent || +		((u_long)rstrm->out_finger + sizeof(u_long) >= +		(u_long)rstrm->out_boundry)) { +		rstrm->frag_sent = FALSE; +		return (flush_out(rstrm, TRUE)); +	} +	len = (u_long)(rstrm->out_finger) - (u_long)(rstrm->frag_header) - +	   sizeof(u_long); +	*(rstrm->frag_header) = htonl((u_long)len | LAST_FRAG); +	rstrm->frag_header = (u_long *)rstrm->out_finger; +	rstrm->out_finger += sizeof(u_long); +	return (TRUE); +} + + +/* + * Internal useful routines + */ +static bool_t +flush_out(rstrm, eor) +	register RECSTREAM *rstrm; +	bool_t eor; +{ +	register u_long eormask = (eor == TRUE) ? LAST_FRAG : 0; +	register u_long len = (u_long)(rstrm->out_finger) -  +		(u_long)(rstrm->frag_header) - sizeof(u_long); + +	*(rstrm->frag_header) = htonl(len | eormask); +	len = (u_long)(rstrm->out_finger) - (u_long)(rstrm->out_base); +	if ((*(rstrm->writeit))(rstrm->tcp_handle, rstrm->out_base, (int)len) +		!= (int)len) +		return (FALSE); +	rstrm->frag_header = (u_long *)rstrm->out_base; +	rstrm->out_finger = (caddr_t)rstrm->out_base + sizeof(u_long); +	return (TRUE); +} + +static bool_t  /* knows nothing about records!  Only about input buffers */ +fill_input_buf(rstrm) +	register RECSTREAM *rstrm; +{ +	register caddr_t where; +	u_int i; +	register int len; + +	where = rstrm->in_base; +	i = (u_int)rstrm->in_boundry % BYTES_PER_XDR_UNIT; +	where += i; +	len = rstrm->in_size - i; +	if ((len = (*(rstrm->readit))(rstrm->tcp_handle, where, len)) == -1) +		return (FALSE); +	rstrm->in_finger = where; +	where += len; +	rstrm->in_boundry = where; +	return (TRUE); +} + +static bool_t  /* knows nothing about records!  Only about input buffers */ +get_input_bytes(rstrm, addr, len) +	register RECSTREAM *rstrm; +	register caddr_t addr; +	register int len; +{ +	register int current; + +	while (len > 0) { +		current = (int)rstrm->in_boundry - (int)rstrm->in_finger; +		if (current == 0) { +			if (! fill_input_buf(rstrm)) +				return (FALSE); +			continue; +		} +		current = (len < current) ? len : current; +		bcopy(rstrm->in_finger, addr, current); +		rstrm->in_finger += current; +		addr += current; +		len -= current; +	} +	return (TRUE); +} + +static bool_t  /* next two bytes of the input stream are treated as a header */ +set_input_fragment(rstrm) +	register RECSTREAM *rstrm; +{ +	u_long header; + +	if (! get_input_bytes(rstrm, (caddr_t)&header, sizeof(header))) +		return (FALSE); +	header = (long)ntohl(header); +	rstrm->last_frag = ((header & LAST_FRAG) == 0) ? FALSE : TRUE; +	rstrm->fbtbc = header & (~LAST_FRAG); +	return (TRUE); +} + +static bool_t  /* consumes input bytes; knows nothing about records! */ +skip_input_bytes(rstrm, cnt) +	register RECSTREAM *rstrm; +	long cnt; +{ +	register int current; + +	while (cnt > 0) { +		current = (int)rstrm->in_boundry - (int)rstrm->in_finger; +		if (current == 0) { +			if (! fill_input_buf(rstrm)) +				return (FALSE); +			continue; +		} +		current = (cnt < current) ? cnt : current; +		rstrm->in_finger += current; +		cnt -= current; +	} +	return (TRUE); +} + +static u_int +fix_buf_size(s) +	register u_int s; +{ + +	if (s < 100) +		s = 4000; +	return (RNDUP(s)); +} diff --git a/lib/librpc/rpc/xdr_reference.c b/lib/librpc/rpc/xdr_reference.c new file mode 100644 index 000000000000..32d91d9999e4 --- /dev/null +++ b/lib/librpc/rpc/xdr_reference.c @@ -0,0 +1,132 @@ +/* @(#)xdr_reference.c	2.1 88/07/29 4.0 RPCSRC */ +/* + * Sun RPC is a product of Sun Microsystems, Inc. and is provided for + * unrestricted use provided that this legend is included on all tape + * media and as a part of the software program in whole or part.  Users + * may copy or modify Sun RPC without charge, but are not authorized + * to license or distribute it to anyone else except as part of a product or + * program developed by the user. + *  + * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE + * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR + * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. + *  + * Sun RPC is provided with no support and without any obligation on the + * part of Sun Microsystems, Inc. to assist in its use, correction, + * modification or enhancement. + *  + * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE + * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC + * OR ANY PART THEREOF. + *  + * In no event will Sun Microsystems, Inc. be liable for any lost revenue + * or profits or other special, indirect and consequential damages, even if + * Sun has been advised of the possibility of such damages. + *  + * Sun Microsystems, Inc. + * 2550 Garcia Avenue + * Mountain View, California  94043 + */ +#if !defined(lint) && defined(SCCSIDS) +static char sccsid[] = "@(#)xdr_reference.c 1.11 87/08/11 SMI"; +#endif + +/* + * xdr_reference.c, Generic XDR routines impelmentation. + * + * Copyright (C) 1987, Sun Microsystems, Inc. + * + * These are the "non-trivial" xdr primitives used to serialize and de-serialize + * "pointers".  See xdr.h for more info on the interface to xdr. + */ + +#include <stdio.h> +#include <rpc/types.h> +#include <rpc/xdr.h> + +#define LASTUNSIGNED	((u_int)0-1) + +/* + * XDR an indirect pointer + * xdr_reference is for recursively translating a structure that is + * referenced by a pointer inside the structure that is currently being + * translated.  pp references a pointer to storage. If *pp is null + * the  necessary storage is allocated. + * size is the sizeof the referneced structure. + * proc is the routine to handle the referenced structure. + */ +bool_t +xdr_reference(xdrs, pp, size, proc) +	register XDR *xdrs; +	caddr_t *pp;		/* the pointer to work on */ +	u_int size;		/* size of the object pointed to */ +	xdrproc_t proc;		/* xdr routine to handle the object */ +{ +	register caddr_t loc = *pp; +	register bool_t stat; + +	if (loc == NULL) +		switch (xdrs->x_op) { +		case XDR_FREE: +			return (TRUE); + +		case XDR_DECODE: +			*pp = loc = (caddr_t) mem_alloc(size); +			if (loc == NULL) { +				(void) fprintf(stderr, +				    "xdr_reference: out of memory\n"); +				return (FALSE); +			} +			bzero(loc, (int)size); +			break; +	} + +	stat = (*proc)(xdrs, loc, LASTUNSIGNED); + +	if (xdrs->x_op == XDR_FREE) { +		mem_free(loc, size); +		*pp = NULL; +	} +	return (stat); +} + + +/* + * xdr_pointer(): + * + * XDR a pointer to a possibly recursive data structure. This + * differs with xdr_reference in that it can serialize/deserialiaze + * trees correctly. + * + *  What's sent is actually a union: + * + *  union object_pointer switch (boolean b) { + *  case TRUE: object_data data; + *  case FALSE: void nothing; + *  } + * + * > objpp: Pointer to the pointer to the object. + * > obj_size: size of the object. + * > xdr_obj: routine to XDR an object. + * + */ +bool_t +xdr_pointer(xdrs,objpp,obj_size,xdr_obj) +	register XDR *xdrs; +	char **objpp; +	u_int obj_size; +	xdrproc_t xdr_obj; +{ + +	bool_t more_data; + +	more_data = (*objpp != NULL); +	if (! xdr_bool(xdrs,&more_data)) { +		return (FALSE); +	} +	if (! more_data) { +		*objpp = NULL; +		return (TRUE); +	} +	return (xdr_reference(xdrs,objpp,obj_size,xdr_obj)); +} diff --git a/lib/librpc/rpc/xdr_stdio.c b/lib/librpc/rpc/xdr_stdio.c new file mode 100644 index 000000000000..694774f6f6d6 --- /dev/null +++ b/lib/librpc/rpc/xdr_stdio.c @@ -0,0 +1,189 @@ +/* @(#)xdr_stdio.c	2.1 88/07/29 4.0 RPCSRC */ +/* + * Sun RPC is a product of Sun Microsystems, Inc. and is provided for + * unrestricted use provided that this legend is included on all tape + * media and as a part of the software program in whole or part.  Users + * may copy or modify Sun RPC without charge, but are not authorized + * to license or distribute it to anyone else except as part of a product or + * program developed by the user. + *  + * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE + * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR + * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. + *  + * Sun RPC is provided with no support and without any obligation on the + * part of Sun Microsystems, Inc. to assist in its use, correction, + * modification or enhancement. + *  + * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE + * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC + * OR ANY PART THEREOF. + *  + * In no event will Sun Microsystems, Inc. be liable for any lost revenue + * or profits or other special, indirect and consequential damages, even if + * Sun has been advised of the possibility of such damages. + *  + * Sun Microsystems, Inc. + * 2550 Garcia Avenue + * Mountain View, California  94043 + */ +#if !defined(lint) && defined(SCCSIDS) +static char sccsid[] = "@(#)xdr_stdio.c 1.16 87/08/11 Copyr 1984 Sun Micro"; +#endif + +/* + * xdr_stdio.c, XDR implementation on standard i/o file. + * + * Copyright (C) 1984, Sun Microsystems, Inc. + * + * This set of routines implements a XDR on a stdio stream. + * XDR_ENCODE serializes onto the stream, XDR_DECODE de-serializes + * from the stream. + */ + +#include <rpc/types.h> +#include <stdio.h> +#include <rpc/xdr.h> + +static bool_t	xdrstdio_getlong(); +static bool_t	xdrstdio_putlong(); +static bool_t	xdrstdio_getbytes(); +static bool_t	xdrstdio_putbytes(); +static u_int	xdrstdio_getpos(); +static bool_t	xdrstdio_setpos(); +static long *	xdrstdio_inline(); +static void	xdrstdio_destroy(); + +/* + * Ops vector for stdio type XDR + */ +static struct xdr_ops	xdrstdio_ops = { +	xdrstdio_getlong,	/* deseraialize a long int */ +	xdrstdio_putlong,	/* seraialize a long int */ +	xdrstdio_getbytes,	/* deserialize counted bytes */ +	xdrstdio_putbytes,	/* serialize counted bytes */ +	xdrstdio_getpos,	/* get offset in the stream */ +	xdrstdio_setpos,	/* set offset in the stream */ +	xdrstdio_inline,	/* prime stream for inline macros */ +	xdrstdio_destroy	/* destroy stream */ +}; + +/* + * Initialize a stdio xdr stream. + * Sets the xdr stream handle xdrs for use on the stream file. + * Operation flag is set to op. + */ +void +xdrstdio_create(xdrs, file, op) +	register XDR *xdrs; +	FILE *file; +	enum xdr_op op; +{ + +	xdrs->x_op = op; +	xdrs->x_ops = &xdrstdio_ops; +	xdrs->x_private = (caddr_t)file; +	xdrs->x_handy = 0; +	xdrs->x_base = 0; +} + +/* + * Destroy a stdio xdr stream. + * Cleans up the xdr stream handle xdrs previously set up by xdrstdio_create. + */ +static void +xdrstdio_destroy(xdrs) +	register XDR *xdrs; +{ +	(void)fflush((FILE *)xdrs->x_private); +	/* xx should we close the file ?? */ +}; + +static bool_t +xdrstdio_getlong(xdrs, lp) +	XDR *xdrs; +	register long *lp; +{ + +	if (fread((caddr_t)lp, sizeof(long), 1, (FILE *)xdrs->x_private) != 1) +		return (FALSE); +#ifndef mc68000 +	*lp = ntohl(*lp); +#endif +	return (TRUE); +} + +static bool_t +xdrstdio_putlong(xdrs, lp) +	XDR *xdrs; +	long *lp; +{ + +#ifndef mc68000 +	long mycopy = htonl(*lp); +	lp = &mycopy; +#endif +	if (fwrite((caddr_t)lp, sizeof(long), 1, (FILE *)xdrs->x_private) != 1) +		return (FALSE); +	return (TRUE); +} + +static bool_t +xdrstdio_getbytes(xdrs, addr, len) +	XDR *xdrs; +	caddr_t addr; +	u_int len; +{ + +	if ((len != 0) && (fread(addr, (int)len, 1, (FILE *)xdrs->x_private) != 1)) +		return (FALSE); +	return (TRUE); +} + +static bool_t +xdrstdio_putbytes(xdrs, addr, len) +	XDR *xdrs; +	caddr_t addr; +	u_int len; +{ + +	if ((len != 0) && (fwrite(addr, (int)len, 1, (FILE *)xdrs->x_private) != 1)) +		return (FALSE); +	return (TRUE); +} + +static u_int +xdrstdio_getpos(xdrs) +	XDR *xdrs; +{ + +	return ((u_int) ftell((FILE *)xdrs->x_private)); +} + +static bool_t +xdrstdio_setpos(xdrs, pos)  +	XDR *xdrs; +	u_int pos; +{  + +	return ((fseek((FILE *)xdrs->x_private, (long)pos, 0) < 0) ? +		FALSE : TRUE); +} + +static long * +xdrstdio_inline(xdrs, len) +	XDR *xdrs; +	u_int len; +{ + +	/* +	 * Must do some work to implement this: must insure +	 * enough data in the underlying stdio buffer, +	 * that the buffer is aligned so that we can indirect through a +	 * long *, and stuff this pointer in xdrs->x_buf.  Doing +	 * a fread or fwrite to a scratch buffer would defeat +	 * most of the gains to be had here and require storage +	 * management on this buffer, so we don't do this. +	 */ +	return (NULL); +} diff --git a/lib/librpc/rpcgen/Makefile b/lib/librpc/rpcgen/Makefile new file mode 100644 index 000000000000..f6d15c3d5a27 --- /dev/null +++ b/lib/librpc/rpcgen/Makefile @@ -0,0 +1,60 @@ +# +# @(#)Makefile	2.1 88/08/01 4.0 RPCSRC +# +# Makefile for rpc protocol compiler +# Copyright (C) 1987, Sun Microsystems, Inc. +# +SRCS= rpc_main.c rpc_hout.c rpc_cout.c rpc_parse.c rpc_scan.c rpc_util.c \ +	rpc_svcout.c rpc_clntout.c +HDRS= rpc_util.h rpc_parse.h rpc_scan.h +OBJS= rpc_main.o rpc_hout.o rpc_cout.o rpc_parse.o rpc_scan.o rpc_util.o \ +	rpc_svcout.o rpc_clntout.o + +GOAL=rpcgen +CFLAGS = -O +DESTDIR= + +$(GOAL): $(OBJS) +	$(CC) $(CFLAGS) $(OBJS) -o $@ + +install: $(GOAL) +	@echo "Installing the RPC Protocol Compiler" +	install -s $(GOAL) $(DESTDIR)/usr/bin + +lint: $(SRCS) $(HDRS) +	lint $(SRCS) + +clean: +	rm -f $(GOAL) $(OBJS) + +depend: $(SRCS) $(HDRS) +	@${CC} ${CFLAGS} -M ${SRCS} > makedep +	@echo '/^# DO NOT DELETE THIS LINE/+1,$$d' >eddep +	@echo '$$r makedep' >>eddep +	@echo 'w' >>eddep +	@cp Makefile makefile.bak +	@ed - Makefile < eddep +	@rm eddep makedep makefile.bak + +depend.42BSD depend.42bsd: +	cp /dev/null x.c +	for i in $(SRCS) ; do \ +              (/bin/grep '^#[         ]*include' x.c $$i | sed \ +                      -e '/\.\.\/h/d' \ +                      -e '/\.\.\/ufs/d' \ +                      -e 's,<\(.*\)>,"/usr/include/\1",' \ +                      -e 's/:[^"]*"\([^"]*\)".*/: \1/' \ +	                  -e 's/\.c/\.o/' >>makedep); done +	echo '/^# DO NOT DELETE THIS LINE/+2,$$d' >eddep +	echo '$$r makedep' >>eddep +	echo 'w' >>eddep +	cp Makefile Makefile.bak +	ed - Makefile < eddep +	rm eddep makedep x.c +	echo '# DEPENDENCIES MUST END AT END OF FILE' >> Makefile +	echo '# IF YOU PUT STUFF HERE IT WILL GO AWAY' >> Makefile +	echo '# see make depend above' >> Makefile + +# DO NOT DELETE THIS LINE + + diff --git a/lib/librpc/rpcgen/rpc_clntout.c b/lib/librpc/rpcgen/rpc_clntout.c new file mode 100644 index 000000000000..555681bd2a3c --- /dev/null +++ b/lib/librpc/rpcgen/rpc_clntout.c @@ -0,0 +1,126 @@ +/* @(#)rpc_clntout.c	2.1 88/08/01 4.0 RPCSRC */ +/* + * Sun RPC is a product of Sun Microsystems, Inc. and is provided for + * unrestricted use provided that this legend is included on all tape + * media and as a part of the software program in whole or part.  Users + * may copy or modify Sun RPC without charge, but are not authorized + * to license or distribute it to anyone else except as part of a product or + * program developed by the user. + *  + * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE + * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR + * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. + *  + * Sun RPC is provided with no support and without any obligation on the + * part of Sun Microsystems, Inc. to assist in its use, correction, + * modification or enhancement. + *  + * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE + * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC + * OR ANY PART THEREOF. + *  + * In no event will Sun Microsystems, Inc. be liable for any lost revenue + * or profits or other special, indirect and consequential damages, even if + * Sun has been advised of the possibility of such damages. + *  + * Sun Microsystems, Inc. + * 2550 Garcia Avenue + * Mountain View, California  94043 + */ +#ifndef lint +static char sccsid[] = "@(#)rpc_clntout.c 1.2 87/06/24 (C) 1987 SMI"; +#endif + +/* + * rpc_clntout.c, Client-stub outputter for the RPC protocol compiler + * Copyright (C) 1987, Sun Microsytsems, Inc. + */ +#include <stdio.h> +#include <strings.h> +#include "rpc_parse.h" +#include "rpc_util.h" + +#define DEFAULT_TIMEOUT 25	/* in seconds */ + +void +write_stubs() +{ +	list *l; +	definition *def; + + 	f_print(fout, + 		"\n/* Default timeout can be changed using clnt_control() */\n"); + 	f_print(fout, "static struct timeval TIMEOUT = { %d, 0 };\n", +		DEFAULT_TIMEOUT); +	for (l = defined; l != NULL; l = l->next) { +		def = (definition *) l->val; +		if (def->def_kind == DEF_PROGRAM) { +			write_program(def); +		} +	} +} + + +static +write_program(def) +	definition *def; +{ +	version_list *vp; +	proc_list *proc; + +	for (vp = def->def.pr.versions; vp != NULL; vp = vp->next) { +		for (proc = vp->procs; proc != NULL; proc = proc->next) { +			f_print(fout, "\n"); +			ptype(proc->res_prefix, proc->res_type, 1); +			f_print(fout, "*\n"); +			pvname(proc->proc_name, vp->vers_num); +			f_print(fout, "(argp, clnt)\n"); +			f_print(fout, "\t"); +			ptype(proc->arg_prefix, proc->arg_type, 1); +			f_print(fout, "*argp;\n"); +			f_print(fout, "\tCLIENT *clnt;\n"); +			f_print(fout, "{\n"); +			printbody(proc); +			f_print(fout, "}\n\n"); +		} +	} +} + +static char * +ampr(type) +	char *type; +{ +	if (isvectordef(type, REL_ALIAS)) { +		return (""); +	} else { +		return ("&"); +	} +} + +static +printbody(proc) +	proc_list *proc; +{ +	f_print(fout, "\tstatic "); +	if (streq(proc->res_type, "void")) { +		f_print(fout, "char "); +	} else { +		ptype(proc->res_prefix, proc->res_type, 0); +	} +	f_print(fout, "res;\n"); +	f_print(fout, "\n"); + 	f_print(fout, "\tbzero((char *)%sres, sizeof(res));\n", + 		ampr(proc->res_type)); +	f_print(fout, +		"\tif (clnt_call(clnt, %s, xdr_%s, argp, xdr_%s, %sres, TIMEOUT) != RPC_SUCCESS) {\n", +		proc->proc_name, stringfix(proc->arg_type), +		stringfix(proc->res_type), ampr(proc->res_type)); +	f_print(fout, "\t\treturn (NULL);\n"); +	f_print(fout, "\t}\n"); +	if (streq(proc->res_type, "void")) { +		f_print(fout, "\treturn ((void *)%sres);\n", +			ampr(proc->res_type)); +	} else { +		f_print(fout, "\treturn (%sres);\n", ampr(proc->res_type)); +	} +} diff --git a/lib/librpc/rpcgen/rpc_cout.c b/lib/librpc/rpcgen/rpc_cout.c new file mode 100644 index 000000000000..86d38652f5b1 --- /dev/null +++ b/lib/librpc/rpcgen/rpc_cout.c @@ -0,0 +1,350 @@ +/* @(#)rpc_cout.c	2.1 88/08/01 4.0 RPCSRC */ +/* + * Sun RPC is a product of Sun Microsystems, Inc. and is provided for + * unrestricted use provided that this legend is included on all tape + * media and as a part of the software program in whole or part.  Users + * may copy or modify Sun RPC without charge, but are not authorized + * to license or distribute it to anyone else except as part of a product or + * program developed by the user. + *  + * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE + * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR + * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. + *  + * Sun RPC is provided with no support and without any obligation on the + * part of Sun Microsystems, Inc. to assist in its use, correction, + * modification or enhancement. + *  + * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE + * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC + * OR ANY PART THEREOF. + *  + * In no event will Sun Microsystems, Inc. be liable for any lost revenue + * or profits or other special, indirect and consequential damages, even if + * Sun has been advised of the possibility of such damages. + *  + * Sun Microsystems, Inc. + * 2550 Garcia Avenue + * Mountain View, California  94043 + */ +#ifndef lint +static char sccsid[] = "@(#)rpc_cout.c 1.8 87/06/24 (C) 1987 SMI"; +#endif + +/* + * rpc_cout.c, XDR routine outputter for the RPC protocol compiler  + * Copyright (C) 1987, Sun Microsystems, Inc.  + */ +#include <stdio.h> +#include <strings.h> +#include "rpc_util.h" +#include "rpc_parse.h" + +/* + * Emit the C-routine for the given definition  + */ +void +emit(def) +	definition *def; +{ +	if (def->def_kind == DEF_PROGRAM || def->def_kind == DEF_CONST) { +		return; +	} +	print_header(def); +	switch (def->def_kind) { +	case DEF_UNION: +		emit_union(def); +		break; +	case DEF_ENUM: +		emit_enum(def); +		break; +	case DEF_STRUCT: +		emit_struct(def); +		break; +	case DEF_TYPEDEF: +		emit_typedef(def); +		break; +	} +	print_trailer(); +} + +static +findtype(def, type) +	definition *def; +	char *type; +{ +	if (def->def_kind == DEF_PROGRAM || def->def_kind == DEF_CONST) { +		return (0); +	} else { +		return (streq(def->def_name, type)); +	} +} + +static +undefined(type) +	char *type; +{ +	definition *def; + +	def = (definition *) FINDVAL(defined, type, findtype); +	return (def == NULL); +} + + +static +print_header(def) +	definition *def; +{ +	space(); +	f_print(fout, "bool_t\n"); +	f_print(fout, "xdr_%s(xdrs, objp)\n", def->def_name); +	f_print(fout, "\tXDR *xdrs;\n"); +	f_print(fout, "\t%s ", def->def_name); +	if (def->def_kind != DEF_TYPEDEF || +	    !isvectordef(def->def.ty.old_type, def->def.ty.rel)) { +		f_print(fout, "*"); +	} +	f_print(fout, "objp;\n"); +	f_print(fout, "{\n"); +} + +static +print_trailer() +{ +	f_print(fout, "\treturn (TRUE);\n"); +	f_print(fout, "}\n"); +	space(); +} + + +static +print_ifopen(indent, name) +	int indent; +	char *name; +{ +	tabify(fout, indent); +	f_print(fout, "if (!xdr_%s(xdrs", name); +} + + +static +print_ifarg(arg) +	char *arg; +{ +	f_print(fout, ", %s", arg); +} + + +static +print_ifsizeof(prefix, type) +	char *prefix; +	char *type; +{ +	if (streq(type, "bool")) { +		f_print(fout, ", sizeof(bool_t), xdr_bool"); +	} else { +		f_print(fout, ", sizeof("); +		if (undefined(type) && prefix) { +			f_print(fout, "%s ", prefix); +		} +		f_print(fout, "%s), xdr_%s", type, type); +	} +} + +static +print_ifclose(indent) +	int indent; +{ +	f_print(fout, ")) {\n"); +	tabify(fout, indent); +	f_print(fout, "\treturn (FALSE);\n"); +	tabify(fout, indent); +	f_print(fout, "}\n"); +} + +static +space() +{ +	f_print(fout, "\n\n"); +} + +static +print_ifstat(indent, prefix, type, rel, amax, objname, name) +	int indent; +	char *prefix; +	char *type; +	relation rel; +	char *amax; +	char *objname; +	char *name; +{ +	char *alt = NULL; + +	switch (rel) { +	case REL_POINTER: +		print_ifopen(indent, "pointer"); +		print_ifarg("(char **)"); +		f_print(fout, "%s", objname); +		print_ifsizeof(prefix, type); +		break; +	case REL_VECTOR: +		if (streq(type, "string")) { +			alt = "string"; +		} else if (streq(type, "opaque")) { +			alt = "opaque"; +		} +		if (alt) { +			print_ifopen(indent, alt); +			print_ifarg(objname); +		} else { +			print_ifopen(indent, "vector"); +			print_ifarg("(char *)"); +			f_print(fout, "%s", objname); +		} +		print_ifarg(amax); +		if (!alt) { +			print_ifsizeof(prefix, type); +		} +		break; +	case REL_ARRAY: +		if (streq(type, "string")) { +			alt = "string"; +		} else if (streq(type, "opaque")) { +			alt = "bytes"; +		} +		if (streq(type, "string")) { +			print_ifopen(indent, alt); +			print_ifarg(objname); +		} else { +			if (alt) { +				print_ifopen(indent, alt); +			} else { +				print_ifopen(indent, "array"); +			} +			print_ifarg("(char **)"); +			if (*objname == '&') { +				f_print(fout, "%s.%s_val, (u_int *)%s.%s_len", +					objname, name, objname, name); +			} else { +				f_print(fout, "&%s->%s_val, (u_int *)&%s->%s_len", +					objname, name, objname, name); +			} +		} +		print_ifarg(amax); +		if (!alt) { +			print_ifsizeof(prefix, type); +		} +		break; +	case REL_ALIAS: +		print_ifopen(indent, type); +		print_ifarg(objname); +		break; +	} +	print_ifclose(indent); +} + + +/* ARGSUSED */ +static +emit_enum(def) +	definition *def; +{ +	print_ifopen(1, "enum"); +	print_ifarg("(enum_t *)objp"); +	print_ifclose(1); +} + + +static +emit_union(def) +	definition *def; +{ +	declaration *dflt; +	case_list *cl; +	declaration *cs; +	char *object; +	char *format = "&objp->%s_u.%s"; + +	print_stat(&def->def.un.enum_decl); +	f_print(fout, "\tswitch (objp->%s) {\n", def->def.un.enum_decl.name); +	for (cl = def->def.un.cases; cl != NULL; cl = cl->next) { +		cs = &cl->case_decl; +		f_print(fout, "\tcase %s:\n", cl->case_name); +		if (!streq(cs->type, "void")) { +			object = alloc(strlen(def->def_name) + strlen(format) + +				       strlen(cs->name) + 1); +			s_print(object, format, def->def_name, cs->name); +			print_ifstat(2, cs->prefix, cs->type, cs->rel, cs->array_max, +				     object, cs->name); +			free(object); +		} +		f_print(fout, "\t\tbreak;\n"); +	} +	dflt = def->def.un.default_decl; +	if (dflt != NULL) { +		if (!streq(dflt->type, "void")) { +			f_print(fout, "\tdefault:\n"); +			object = alloc(strlen(def->def_name) + strlen(format) + +				       strlen(dflt->name) + 1); +			s_print(object, format, def->def_name, dflt->name); +			print_ifstat(2, dflt->prefix, dflt->type, dflt->rel, +				     dflt->array_max, object, dflt->name); +			free(object); +			f_print(fout, "\t\tbreak;\n"); +		} +	} else { +		f_print(fout, "\tdefault:\n"); +		f_print(fout, "\t\treturn (FALSE);\n"); +	} +	f_print(fout, "\t}\n"); +} + + + +static +emit_struct(def) +	definition *def; +{ +	decl_list *dl; + +	for (dl = def->def.st.decls; dl != NULL; dl = dl->next) { +		print_stat(&dl->decl); +	} +} + + + + +static +emit_typedef(def) +	definition *def; +{ +	char *prefix = def->def.ty.old_prefix; +	char *type = def->def.ty.old_type; +	char *amax = def->def.ty.array_max; +	relation rel = def->def.ty.rel; + +	print_ifstat(1, prefix, type, rel, amax, "objp", def->def_name); +} + + + + + +static +print_stat(dec) +	declaration *dec; +{ +	char *prefix = dec->prefix; +	char *type = dec->type; +	char *amax = dec->array_max; +	relation rel = dec->rel; +	char name[256]; + +	if (isvectordef(type, rel)) { +		s_print(name, "objp->%s", dec->name); +	} else { +		s_print(name, "&objp->%s", dec->name); +	} +	print_ifstat(1, prefix, type, rel, amax, name, dec->name); +} diff --git a/lib/librpc/rpcgen/rpc_hout.c b/lib/librpc/rpcgen/rpc_hout.c new file mode 100644 index 000000000000..1bf009738d5a --- /dev/null +++ b/lib/librpc/rpcgen/rpc_hout.c @@ -0,0 +1,370 @@ +/* @(#)rpc_hout.c	2.1 88/08/01 4.0 RPCSRC */ +/* + * Sun RPC is a product of Sun Microsystems, Inc. and is provided for + * unrestricted use provided that this legend is included on all tape + * media and as a part of the software program in whole or part.  Users + * may copy or modify Sun RPC without charge, but are not authorized + * to license or distribute it to anyone else except as part of a product or + * program developed by the user. + *  + * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE + * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR + * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. + *  + * Sun RPC is provided with no support and without any obligation on the + * part of Sun Microsystems, Inc. to assist in its use, correction, + * modification or enhancement. + *  + * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE + * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC + * OR ANY PART THEREOF. + *  + * In no event will Sun Microsystems, Inc. be liable for any lost revenue + * or profits or other special, indirect and consequential damages, even if + * Sun has been advised of the possibility of such damages. + *  + * Sun Microsystems, Inc. + * 2550 Garcia Avenue + * Mountain View, California  94043 + */ +#ifndef lint +static char sccsid[] = "@(#)rpc_hout.c 1.6 87/07/28 (C) 1987 SMI"; +#endif + +/* + * rpc_hout.c, Header file outputter for the RPC protocol compiler  + * Copyright (C) 1987, Sun Microsystems, Inc.  + */ +#include <stdio.h> +#include <ctype.h> +#include "rpc_util.h" +#include "rpc_parse.h" + + +/* + * Print the C-version of an xdr definition  + */ +void +print_datadef(def) +	definition *def; +{ +	if (def->def_kind != DEF_CONST) { +		f_print(fout, "\n"); +	} +	switch (def->def_kind) { +	case DEF_STRUCT: +		pstructdef(def); +		break; +	case DEF_UNION: +		puniondef(def); +		break; +	case DEF_ENUM: +		penumdef(def); +		break; +	case DEF_TYPEDEF: +		ptypedef(def); +		break; +	case DEF_PROGRAM: +		pprogramdef(def); +		break; +	case DEF_CONST: +		pconstdef(def); +		break; +	} +	if (def->def_kind != DEF_PROGRAM && def->def_kind != DEF_CONST) { +		f_print(fout, "bool_t xdr_%s();\n", def->def_name); +	} +	if (def->def_kind != DEF_CONST) { +		f_print(fout, "\n"); +	} +} + +static +pconstdef(def) +	definition *def; +{ +	pdefine(def->def_name, def->def.co); +} + +static +pstructdef(def) +	definition *def; +{ +	decl_list *l; +	char *name = def->def_name; + +	f_print(fout, "struct %s {\n", name); +	for (l = def->def.st.decls; l != NULL; l = l->next) { +		pdeclaration(name, &l->decl, 1); +	} +	f_print(fout, "};\n"); +	f_print(fout, "typedef struct %s %s;\n", name, name); +} + +static +puniondef(def) +	definition *def; +{ +	case_list *l; +	char *name = def->def_name; +	declaration *decl; + +	f_print(fout, "struct %s {\n", name); +	decl = &def->def.un.enum_decl; +	if (streq(decl->type, "bool")) { +		f_print(fout, "\tbool_t %s;\n", decl->name); +	} else { +		f_print(fout, "\t%s %s;\n", decl->type, decl->name); +	} +	f_print(fout, "\tunion {\n"); +	for (l = def->def.un.cases; l != NULL; l = l->next) { +		pdeclaration(name, &l->case_decl, 2); +	} +	decl = def->def.un.default_decl; +	if (decl && !streq(decl->type, "void")) { +		pdeclaration(name, decl, 2); +	} +	f_print(fout, "\t} %s_u;\n", name); +	f_print(fout, "};\n"); +	f_print(fout, "typedef struct %s %s;\n", name, name); +} + + + +static +pdefine(name, num) +	char *name; +	char *num; +{ +	f_print(fout, "#define %s %s\n", name, num); +} + +static +puldefine(name, num) +	char *name; +	char *num; +{ +	f_print(fout, "#define %s ((u_long)%s)\n", name, num); +} + +static +define_printed(stop, start) +	proc_list *stop; +	version_list *start; +{ +	version_list *vers; +	proc_list *proc; + +	for (vers = start; vers != NULL; vers = vers->next) { +		for (proc = vers->procs; proc != NULL; proc = proc->next) { +			if (proc == stop) { +				return (0); +			} else if (streq(proc->proc_name, stop->proc_name)) { +				return (1); +			} +		} +	} +	abort(); +	/* NOTREACHED */ +} + + +static +pprogramdef(def) +	definition *def; +{ +	version_list *vers; +	proc_list *proc; + +	puldefine(def->def_name, def->def.pr.prog_num); +	for (vers = def->def.pr.versions; vers != NULL; vers = vers->next) { +		puldefine(vers->vers_name, vers->vers_num); +		for (proc = vers->procs; proc != NULL; proc = proc->next) { +			if (!define_printed(proc, def->def.pr.versions)) { +				puldefine(proc->proc_name, proc->proc_num); +			} +			pprocdef(proc, vers); +		} +	} +} + + +pprocdef(proc, vp) +	proc_list *proc; +	version_list *vp; +{ +	f_print(fout, "extern "); +	if (proc->res_prefix) { +		if (streq(proc->res_prefix, "enum")) { +			f_print(fout, "enum "); +		} else { +			f_print(fout, "struct "); +		} +	} +	if (streq(proc->res_type, "bool")) { +		f_print(fout, "bool_t *"); +	} else if (streq(proc->res_type, "string")) { +		f_print(fout, "char **"); +	} else { +		f_print(fout, "%s *", fixtype(proc->res_type)); +	} +	pvname(proc->proc_name, vp->vers_num); +	f_print(fout, "();\n"); +} + +static +penumdef(def) +	definition *def; +{ +	char *name = def->def_name; +	enumval_list *l; +	char *last = NULL; +	int count = 0; + +	f_print(fout, "enum %s {\n", name); +	for (l = def->def.en.vals; l != NULL; l = l->next) { +		f_print(fout, "\t%s", l->name); +		if (l->assignment) { +			f_print(fout, " = %s", l->assignment); +			last = l->assignment; +			count = 1; +		} else { +			if (last == NULL) { +				f_print(fout, " = %d", count++); +			} else { +				f_print(fout, " = %s + %d", last, count++); +			} +		} +		f_print(fout, ",\n"); +	} +	f_print(fout, "};\n"); +	f_print(fout, "typedef enum %s %s;\n", name, name); +} + +static +ptypedef(def) +	definition *def; +{ +	char *name = def->def_name; +	char *old = def->def.ty.old_type; +	char prefix[8];	/* enough to contain "struct ", including NUL */ +	relation rel = def->def.ty.rel; + + +	if (!streq(name, old)) { +		if (streq(old, "string")) { +			old = "char"; +			rel = REL_POINTER; +		} else if (streq(old, "opaque")) { +			old = "char"; +		} else if (streq(old, "bool")) { +			old = "bool_t"; +		} +		if (undefined2(old, name) && def->def.ty.old_prefix) { +			s_print(prefix, "%s ", def->def.ty.old_prefix); +		} else { +			prefix[0] = 0; +		} +		f_print(fout, "typedef "); +		switch (rel) { +		case REL_ARRAY: +			f_print(fout, "struct {\n"); +			f_print(fout, "\tu_int %s_len;\n", name); +			f_print(fout, "\t%s%s *%s_val;\n", prefix, old, name); +			f_print(fout, "} %s", name); +			break; +		case REL_POINTER: +			f_print(fout, "%s%s *%s", prefix, old, name); +			break; +		case REL_VECTOR: +			f_print(fout, "%s%s %s[%s]", prefix, old, name, +				def->def.ty.array_max); +			break; +		case REL_ALIAS: + 			f_print(fout, "%s%s %s", prefix, old, name); +			break; +		} +		f_print(fout, ";\n"); +	} +} + + +static +pdeclaration(name, dec, tab) +	char *name; +	declaration *dec; +	int tab; +{ +	char buf[8];	/* enough to hold "struct ", include NUL */ +	char *prefix; +	char *type; + +	if (streq(dec->type, "void")) { +		return; +	} +	tabify(fout, tab); +	if (streq(dec->type, name) && !dec->prefix) { +		f_print(fout, "struct "); +	} +	if (streq(dec->type, "string")) { +		f_print(fout, "char *%s", dec->name); +	} else { +		prefix = ""; +		if (streq(dec->type, "bool")) { +			type = "bool_t"; +		} else if (streq(dec->type, "opaque")) { +			type = "char"; +		} else { +			if (dec->prefix) { +				s_print(buf, "%s ", dec->prefix); +				prefix = buf; +			} +			type = dec->type; +		} +		switch (dec->rel) { +		case REL_ALIAS: +			f_print(fout, "%s%s %s", prefix, type, dec->name); +			break; +		case REL_VECTOR: +			f_print(fout, "%s%s %s[%s]", prefix, type, dec->name, +				dec->array_max); +			break; +		case REL_POINTER: +			f_print(fout, "%s%s *%s", prefix, type, dec->name); +			break; +		case REL_ARRAY: +			f_print(fout, "struct {\n"); +			tabify(fout, tab); +			f_print(fout, "\tu_int %s_len;\n", dec->name); +			tabify(fout, tab); +			f_print(fout, "\t%s%s *%s_val;\n", prefix, type, dec->name); +			tabify(fout, tab); +			f_print(fout, "} %s", dec->name); +			break; +		} +	} +	f_print(fout, ";\n"); +} + + + +static +undefined2(type, stop) +	char *type; +	char *stop; +{ +	list *l; +	definition *def; + +	for (l = defined; l != NULL; l = l->next) { +		def = (definition *) l->val; +		if (def->def_kind != DEF_PROGRAM) { +			if (streq(def->def_name, stop)) { +				return (1); +			} else if (streq(def->def_name, type)) { +				return (0); +			} +		} +	} +	return (1); +} diff --git a/lib/librpc/rpcgen/rpc_main.c b/lib/librpc/rpcgen/rpc_main.c new file mode 100644 index 000000000000..795bf2aa5703 --- /dev/null +++ b/lib/librpc/rpcgen/rpc_main.c @@ -0,0 +1,433 @@ +/* @(#)rpc_main.c	2.2 88/08/01 4.0 RPCSRC */ +/* + * Sun RPC is a product of Sun Microsystems, Inc. and is provided for + * unrestricted use provided that this legend is included on all tape + * media and as a part of the software program in whole or part.  Users + * may copy or modify Sun RPC without charge, but are not authorized + * to license or distribute it to anyone else except as part of a product or + * program developed by the user. + *  + * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE + * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR + * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. + *  + * Sun RPC is provided with no support and without any obligation on the + * part of Sun Microsystems, Inc. to assist in its use, correction, + * modification or enhancement. + *  + * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE + * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC + * OR ANY PART THEREOF. + *  + * In no event will Sun Microsystems, Inc. be liable for any lost revenue + * or profits or other special, indirect and consequential damages, even if + * Sun has been advised of the possibility of such damages. + *  + * Sun Microsystems, Inc. + * 2550 Garcia Avenue + * Mountain View, California  94043 + */ +#ifndef lint +static char sccsid[] = "@(#)rpc_main.c 1.7 87/06/24 (C) 1987 SMI"; +#endif + +/* + * rpc_main.c, Top level of the RPC protocol compiler.  + * Copyright (C) 1987, Sun Microsystems, Inc.  + */ + +#include <stdio.h> +#include <strings.h> +#include <sys/file.h> +#include "rpc_util.h" +#include "rpc_parse.h" +#include "rpc_scan.h" + +#define EXTEND	1		/* alias for TRUE */ + +struct commandline { +	int cflag; +	int hflag; +	int lflag; +	int sflag; +	int mflag; +	char *infile; +	char *outfile; +}; + +static char *cmdname; +static char CPP[] = "/lib/cpp"; +static char CPPFLAGS[] = "-C"; +static char *allv[] = { +	"rpcgen", "-s", "udp", "-s", "tcp", +}; +static int allc = sizeof(allv)/sizeof(allv[0]); + +main(argc, argv) +	int argc; +	char *argv[]; + +{ +	struct commandline cmd; + +	if (!parseargs(argc, argv, &cmd)) { +		f_print(stderr, +			"usage: %s infile\n", cmdname); +		f_print(stderr, +			"       %s [-c | -h | -l | -m] [-o outfile] [infile]\n", +			cmdname); +		f_print(stderr, +			"       %s [-s udp|tcp]* [-o outfile] [infile]\n", +			cmdname); +		exit(1); +	} +	if (cmd.cflag) { +		c_output(cmd.infile, "-DRPC_XDR", !EXTEND, cmd.outfile); +	} else if (cmd.hflag) { +		h_output(cmd.infile, "-DRPC_HDR", !EXTEND, cmd.outfile); +	} else if (cmd.lflag) { +		l_output(cmd.infile, "-DRPC_CLNT", !EXTEND, cmd.outfile); +	} else if (cmd.sflag || cmd.mflag) { +		s_output(argc, argv, cmd.infile, "-DRPC_SVC", !EXTEND, +			 cmd.outfile, cmd.mflag); +	} else { +		c_output(cmd.infile, "-DRPC_XDR", EXTEND, "_xdr.c"); +		reinitialize(); +		h_output(cmd.infile, "-DRPC_HDR", EXTEND, ".h"); +		reinitialize(); +		l_output(cmd.infile, "-DRPC_CLNT", EXTEND, "_clnt.c"); +		reinitialize(); +		s_output(allc, allv, cmd.infile, "-DRPC_SVC", EXTEND, +			 "_svc.c", cmd.mflag); +	} +	exit(0); +} + +/* + * add extension to filename  + */ +static char * +extendfile(file, ext) +	char *file; +	char *ext; +{ +	char *res; +	char *p; + +	res = alloc(strlen(file) + strlen(ext) + 1); +	if (res == NULL) { +		abort(); +	} +	p = rindex(file, '.'); +	if (p == NULL) { +		p = file + strlen(file); +	} +	(void) strcpy(res, file); +	(void) strcpy(res + (p - file), ext); +	return (res); +} + +/* + * Open output file with given extension  + */ +static +open_output(infile, outfile) +	char *infile; +	char *outfile; +{ +	if (outfile == NULL) { +		fout = stdout; +		return; +	} +	if (infile != NULL && streq(outfile, infile)) { +		f_print(stderr, "%s: output would overwrite %s\n", cmdname, +			infile); +		crash(); +	} +	fout = fopen(outfile, "w"); +	if (fout == NULL) { +		f_print(stderr, "%s: unable to open ", cmdname); +		perror(outfile); +		crash(); +	} +	record_open(outfile); +} + +/* + * Open input file with given define for C-preprocessor  + */ +static +open_input(infile, define) +	char *infile; +	char *define; +{ +	int pd[2]; + +	infilename = (infile == NULL) ? "<stdin>" : infile; +	(void) pipe(pd); +	switch (fork()) { +	case 0: +		(void) close(1); +		(void) dup2(pd[1], 1); +		(void) close(pd[0]); +		execl(CPP, CPP, CPPFLAGS, define, infile, NULL); +		perror("execl"); +		exit(1); +	case -1: +		perror("fork"); +		exit(1); +	} +	(void) close(pd[1]); +	fin = fdopen(pd[0], "r"); +	if (fin == NULL) { +		f_print(stderr, "%s: ", cmdname); +		perror(infilename); +		crash(); +	} +} + +/* + * Compile into an XDR routine output file + */ +static +c_output(infile, define, extend, outfile) +	char *infile; +	char *define; +	int extend; +	char *outfile; +{ +	definition *def; +	char *include; +	char *outfilename; +	long tell; + +	open_input(infile, define);	 +	outfilename = extend ? extendfile(infile, outfile) : outfile; +	open_output(infile, outfilename); +	f_print(fout, "#include <rpc/rpc.h>\n"); +	if (infile && (include = extendfile(infile, ".h"))) { +		f_print(fout, "#include \"%s\"\n", include); +		free(include); +	} +	tell = ftell(fout); +	while (def = get_definition()) { +		emit(def); +	} +	if (extend && tell == ftell(fout)) { +		(void) unlink(outfilename); +	} +} + +/* + * Compile into an XDR header file + */ +static +h_output(infile, define, extend, outfile) +	char *infile; +	char *define; +	int extend; +	char *outfile; +{ +	definition *def; +	char *outfilename; +	long tell; + +	open_input(infile, define); +	outfilename =  extend ? extendfile(infile, outfile) : outfile; +	open_output(infile, outfilename); +	tell = ftell(fout); +	while (def = get_definition()) { +		print_datadef(def); +	} +	if (extend && tell == ftell(fout)) { +		(void) unlink(outfilename); +	} +} + +/* + * Compile into an RPC service + */ +static +s_output(argc, argv, infile, define, extend, outfile, nomain) +	int argc; +	char *argv[]; +	char *infile; +	char *define; +	int extend; +	char *outfile; +	int nomain; +{ +	char *include; +	definition *def; +	int foundprogram; +	char *outfilename; + +	open_input(infile, define); +	outfilename = extend ? extendfile(infile, outfile) : outfile; +	open_output(infile, outfilename); +	f_print(fout, "#include <stdio.h>\n"); +	f_print(fout, "#include <rpc/rpc.h>\n"); +	if (infile && (include = extendfile(infile, ".h"))) { +		f_print(fout, "#include \"%s\"\n", include); +		free(include); +	} +	foundprogram = 0; +	while (def = get_definition()) { +		foundprogram |= (def->def_kind == DEF_PROGRAM); +	} +	if (extend && !foundprogram) { +		(void) unlink(outfilename); +		return; +	} +	if (nomain) { +		write_programs((char *)NULL); +	} else { +		write_most(); +		do_registers(argc, argv); +		write_rest(); +		write_programs("static"); +	} +} + +static +l_output(infile, define, extend, outfile) +	char *infile; +	char *define; +	int extend; +	char *outfile; +{ +	char *include; +	definition *def; +	int foundprogram; +	char *outfilename; + +	open_input(infile, define); +	outfilename = extend ? extendfile(infile, outfile) : outfile; +	open_output(infile, outfilename); +	f_print(fout, "#include <rpc/rpc.h>\n"); +	if (infile && (include = extendfile(infile, ".h"))) { +		f_print(fout, "#include \"%s\"\n", include); +		free(include); +	} +	foundprogram = 0; +	while (def = get_definition()) { +		foundprogram |= (def->def_kind == DEF_PROGRAM); +	} +	if (extend && !foundprogram) { +		(void) unlink(outfilename); +		return; +	} +	write_stubs(); +} + +/* + * Perform registrations for service output  + */ +static +do_registers(argc, argv) +	int argc; +	char *argv[]; + +{ +	int i; + +	for (i = 1; i < argc; i++) { +		if (streq(argv[i], "-s")) { +			write_register(argv[i + 1]); +			i++; +		} +	} +} + +/* + * Parse command line arguments  + */ +static +parseargs(argc, argv, cmd) +	int argc; +	char *argv[]; +	struct commandline *cmd; + +{ +	int i; +	int j; +	char c; +	char flag[(1 << 8 * sizeof(char))]; +	int nflags; + +	cmdname = argv[0]; +	cmd->infile = cmd->outfile = NULL; +	if (argc < 2) { +		return (0); +	} +	flag['c'] = 0; +	flag['h'] = 0; +	flag['s'] = 0; +	flag['o'] = 0; +	flag['l'] = 0; +	flag['m'] = 0; +	for (i = 1; i < argc; i++) { +		if (argv[i][0] != '-') { +			if (cmd->infile) { +				return (0); +			} +			cmd->infile = argv[i]; +		} else { +			for (j = 1; argv[i][j] != 0; j++) { +				c = argv[i][j]; +				switch (c) { +				case 'c': +				case 'h': +				case 'l': +				case 'm': +					if (flag[c]) { +						return (0); +					} +					flag[c] = 1; +					break; +				case 'o': +				case 's': +					if (argv[i][j - 1] != '-' ||  +					    argv[i][j + 1] != 0) { +						return (0); +					} +					flag[c] = 1; +					if (++i == argc) { +						return (0); +					} +					if (c == 's') { +						if (!streq(argv[i], "udp") && +						    !streq(argv[i], "tcp")) { +							return (0); +						} +					} else if (c == 'o') { +						if (cmd->outfile) { +							return (0); +						} +						cmd->outfile = argv[i]; +					} +					goto nextarg; + +				default: +					return (0); +				} +			} +	nextarg: +			; +		} +	} +	cmd->cflag = flag['c']; +	cmd->hflag = flag['h']; +	cmd->sflag = flag['s']; +	cmd->lflag = flag['l']; +	cmd->mflag = flag['m']; +	nflags = cmd->cflag + cmd->hflag + cmd->sflag + cmd->lflag + cmd->mflag; +	if (nflags == 0) { +		if (cmd->outfile != NULL || cmd->infile == NULL) { +			return (0); +		} +	} else if (nflags > 1) { +		return (0); +	} +	return (1); +} diff --git a/lib/librpc/rpcgen/rpc_parse.c b/lib/librpc/rpcgen/rpc_parse.c new file mode 100644 index 000000000000..9e4663fb3634 --- /dev/null +++ b/lib/librpc/rpcgen/rpc_parse.c @@ -0,0 +1,419 @@ +/* @(#)rpc_parse.c	2.1 88/08/01 4.0 RPCSRC */ +/* + * Sun RPC is a product of Sun Microsystems, Inc. and is provided for + * unrestricted use provided that this legend is included on all tape + * media and as a part of the software program in whole or part.  Users + * may copy or modify Sun RPC without charge, but are not authorized + * to license or distribute it to anyone else except as part of a product or + * program developed by the user. + *  + * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE + * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR + * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. + *  + * Sun RPC is provided with no support and without any obligation on the + * part of Sun Microsystems, Inc. to assist in its use, correction, + * modification or enhancement. + *  + * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE + * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC + * OR ANY PART THEREOF. + *  + * In no event will Sun Microsystems, Inc. be liable for any lost revenue + * or profits or other special, indirect and consequential damages, even if + * Sun has been advised of the possibility of such damages. + *  + * Sun Microsystems, Inc. + * 2550 Garcia Avenue + * Mountain View, California  94043 + */ +#ifndef lint +static char sccsid[] = "@(#)rpc_parse.c 1.4 87/04/28 (C) 1987 SMI"; +#endif + +/* + * rpc_parse.c, Parser for the RPC protocol compiler  + * Copyright (C) 1987 Sun Microsystems, Inc. + */ +#include <stdio.h> +#include "rpc_util.h" +#include "rpc_scan.h" +#include "rpc_parse.h" + +/* + * return the next definition you see + */ +definition * +get_definition() +{ +	definition *defp; +	token tok; + +	defp = ALLOC(definition); +	get_token(&tok); +	switch (tok.kind) { +	case TOK_STRUCT: +		def_struct(defp); +		break; +	case TOK_UNION: +		def_union(defp); +		break; +	case TOK_TYPEDEF: +		def_typedef(defp); +		break; +	case TOK_ENUM: +		def_enum(defp); +		break; +	case TOK_PROGRAM: +		def_program(defp); +		break; +	case TOK_CONST: +		def_const(defp); +		break; +	case TOK_EOF: +		return (NULL); +		break; +	default: +		error("definition keyword expected"); +	} +	scan(TOK_SEMICOLON, &tok); +	isdefined(defp); +	return (defp); +} + +static +isdefined(defp) +	definition *defp; +{ +	STOREVAL(&defined, defp); +} + + +static +def_struct(defp) +	definition *defp; +{ +	token tok; +	declaration dec; +	decl_list *decls; +	decl_list **tailp; + +	defp->def_kind = DEF_STRUCT; + +	scan(TOK_IDENT, &tok); +	defp->def_name = tok.str; +	scan(TOK_LBRACE, &tok); +	tailp = &defp->def.st.decls; +	do { +		get_declaration(&dec, DEF_STRUCT); +		decls = ALLOC(decl_list); +		decls->decl = dec; +		*tailp = decls; +		tailp = &decls->next; +		scan(TOK_SEMICOLON, &tok); +		peek(&tok); +	} while (tok.kind != TOK_RBRACE); +	get_token(&tok); +	*tailp = NULL; +} + +static +def_program(defp) +	definition *defp; +{ +	token tok; +	version_list *vlist; +	version_list **vtailp; +	proc_list *plist; +	proc_list **ptailp; + +	defp->def_kind = DEF_PROGRAM; +	scan(TOK_IDENT, &tok); +	defp->def_name = tok.str; +	scan(TOK_LBRACE, &tok); +	vtailp = &defp->def.pr.versions; +	scan(TOK_VERSION, &tok); +	do { +		scan(TOK_IDENT, &tok); +		vlist = ALLOC(version_list); +		vlist->vers_name = tok.str; +		scan(TOK_LBRACE, &tok); +		ptailp = &vlist->procs; +		do { +			plist = ALLOC(proc_list); +			get_type(&plist->res_prefix, &plist->res_type, DEF_PROGRAM); +			if (streq(plist->res_type, "opaque")) { +				error("illegal result type"); +			} +			scan(TOK_IDENT, &tok); +			plist->proc_name = tok.str; +			scan(TOK_LPAREN, &tok); +			get_type(&plist->arg_prefix, &plist->arg_type, DEF_PROGRAM); +			if (streq(plist->arg_type, "opaque")) { +				error("illegal argument type"); +			} +			scan(TOK_RPAREN, &tok); +			scan(TOK_EQUAL, &tok); +			scan_num(&tok); +			scan(TOK_SEMICOLON, &tok); +			plist->proc_num = tok.str; +			*ptailp = plist; +			ptailp = &plist->next; +			peek(&tok); +		} while (tok.kind != TOK_RBRACE); +		*vtailp = vlist; +		vtailp = &vlist->next; +		scan(TOK_RBRACE, &tok); +		scan(TOK_EQUAL, &tok); +		scan_num(&tok); +		vlist->vers_num = tok.str; +		scan(TOK_SEMICOLON, &tok); +		scan2(TOK_VERSION, TOK_RBRACE, &tok); +	} while (tok.kind == TOK_VERSION); +	scan(TOK_EQUAL, &tok); +	scan_num(&tok); +	defp->def.pr.prog_num = tok.str; +	*vtailp = NULL; +} + +static +def_enum(defp) +	definition *defp; +{ +	token tok; +	enumval_list *elist; +	enumval_list **tailp; + +	defp->def_kind = DEF_ENUM; +	scan(TOK_IDENT, &tok); +	defp->def_name = tok.str; +	scan(TOK_LBRACE, &tok); +	tailp = &defp->def.en.vals; +	do { +		scan(TOK_IDENT, &tok); +		elist = ALLOC(enumval_list); +		elist->name = tok.str; +		elist->assignment = NULL; +		scan3(TOK_COMMA, TOK_RBRACE, TOK_EQUAL, &tok); +		if (tok.kind == TOK_EQUAL) { +			scan_num(&tok); +			elist->assignment = tok.str; +			scan2(TOK_COMMA, TOK_RBRACE, &tok); +		} +		*tailp = elist; +		tailp = &elist->next; +	} while (tok.kind != TOK_RBRACE); +	*tailp = NULL; +} + +static +def_const(defp) +	definition *defp; +{ +	token tok; + +	defp->def_kind = DEF_CONST; +	scan(TOK_IDENT, &tok); +	defp->def_name = tok.str; +	scan(TOK_EQUAL, &tok); +	scan2(TOK_IDENT, TOK_STRCONST, &tok); +	defp->def.co = tok.str; +} + +static +def_union(defp) +	definition *defp; +{ +	token tok; +	declaration dec; +	case_list *cases; +	case_list **tailp; + +	defp->def_kind = DEF_UNION; +	scan(TOK_IDENT, &tok); +	defp->def_name = tok.str; +	scan(TOK_SWITCH, &tok); +	scan(TOK_LPAREN, &tok); +	get_declaration(&dec, DEF_UNION); +	defp->def.un.enum_decl = dec; +	tailp = &defp->def.un.cases; +	scan(TOK_RPAREN, &tok); +	scan(TOK_LBRACE, &tok); +	scan(TOK_CASE, &tok); +	while (tok.kind == TOK_CASE) { +		scan(TOK_IDENT, &tok); +		cases = ALLOC(case_list); +		cases->case_name = tok.str; +		scan(TOK_COLON, &tok); +		get_declaration(&dec, DEF_UNION); +		cases->case_decl = dec; +		*tailp = cases; +		tailp = &cases->next; +		scan(TOK_SEMICOLON, &tok); +		scan3(TOK_CASE, TOK_DEFAULT, TOK_RBRACE, &tok); +	} +	*tailp = NULL; +	if (tok.kind == TOK_DEFAULT) { +		scan(TOK_COLON, &tok); +		get_declaration(&dec, DEF_UNION); +		defp->def.un.default_decl = ALLOC(declaration); +		*defp->def.un.default_decl = dec; +		scan(TOK_SEMICOLON, &tok); +		scan(TOK_RBRACE, &tok); +	} else { +		defp->def.un.default_decl = NULL; +	} +} + + +static +def_typedef(defp) +	definition *defp; +{ +	declaration dec; + +	defp->def_kind = DEF_TYPEDEF; +	get_declaration(&dec, DEF_TYPEDEF); +	defp->def_name = dec.name; +	defp->def.ty.old_prefix = dec.prefix; +	defp->def.ty.old_type = dec.type; +	defp->def.ty.rel = dec.rel; +	defp->def.ty.array_max = dec.array_max; +} + + +static +get_declaration(dec, dkind) +	declaration *dec; +	defkind dkind; +{ +	token tok; + +	get_type(&dec->prefix, &dec->type, dkind); +	dec->rel = REL_ALIAS; +	if (streq(dec->type, "void")) { +		return; +	} +	scan2(TOK_STAR, TOK_IDENT, &tok); +	if (tok.kind == TOK_STAR) { +		dec->rel = REL_POINTER; +		scan(TOK_IDENT, &tok); +	} +	dec->name = tok.str; +	if (peekscan(TOK_LBRACKET, &tok)) { +		if (dec->rel == REL_POINTER) { +			error("no array-of-pointer declarations -- use typedef"); +		} +		dec->rel = REL_VECTOR; +		scan_num(&tok); +		dec->array_max = tok.str; +		scan(TOK_RBRACKET, &tok); +	} else if (peekscan(TOK_LANGLE, &tok)) { +		if (dec->rel == REL_POINTER) { +			error("no array-of-pointer declarations -- use typedef"); +		} +		dec->rel = REL_ARRAY; +		if (peekscan(TOK_RANGLE, &tok)) { +			dec->array_max = "~0";	/* unspecified size, use max */ +		} else { +			scan_num(&tok); +			dec->array_max = tok.str; +			scan(TOK_RANGLE, &tok); +		} +	} +	if (streq(dec->type, "opaque")) { +		if (dec->rel != REL_ARRAY && dec->rel != REL_VECTOR) { +			error("array declaration expected"); +		} +	} else if (streq(dec->type, "string")) { +		if (dec->rel != REL_ARRAY) { +			error("variable-length array declaration expected"); +		} +	} +} + + +static +get_type(prefixp, typep, dkind) +	char **prefixp; +	char **typep; +	defkind dkind; +{ +	token tok; + +	*prefixp = NULL; +	get_token(&tok); +	switch (tok.kind) { +	case TOK_IDENT: +		*typep = tok.str; +		break; +	case TOK_STRUCT: +	case TOK_ENUM: +	case TOK_UNION: +		*prefixp = tok.str; +		scan(TOK_IDENT, &tok); +		*typep = tok.str; +		break; +	case TOK_UNSIGNED: +		unsigned_dec(typep); +		break; +	case TOK_SHORT: +		*typep = "short"; +		(void) peekscan(TOK_INT, &tok); +		break; +	case TOK_LONG: +		*typep = "long"; +		(void) peekscan(TOK_INT, &tok); +		break; +	case TOK_VOID: +		if (dkind != DEF_UNION && dkind != DEF_PROGRAM) { +			error("voids allowed only inside union and program definitions"); +		} +		*typep = tok.str; +		break; +	case TOK_STRING: +	case TOK_OPAQUE: +	case TOK_CHAR: +	case TOK_INT: +	case TOK_FLOAT: +	case TOK_DOUBLE: +	case TOK_BOOL: +		*typep = tok.str; +		break; +	default: +		error("expected type specifier"); +	} +} + + +static +unsigned_dec(typep) +	char **typep; +{ +	token tok; + +	peek(&tok); +	switch (tok.kind) { +	case TOK_CHAR: +		get_token(&tok); +		*typep = "u_char"; +		break; +	case TOK_SHORT: +		get_token(&tok); +		*typep = "u_short"; +		(void) peekscan(TOK_INT, &tok); +		break; +	case TOK_LONG: +		get_token(&tok); +		*typep = "u_long"; +		(void) peekscan(TOK_INT, &tok); +		break; +	case TOK_INT: +		get_token(&tok); +		*typep = "u_int"; +		break; +	default: +		*typep = "u_int"; +		break; +	} +} diff --git a/lib/librpc/rpcgen/rpc_parse.h b/lib/librpc/rpcgen/rpc_parse.h new file mode 100644 index 000000000000..b53cc56ff833 --- /dev/null +++ b/lib/librpc/rpcgen/rpc_parse.h @@ -0,0 +1,157 @@ +/* + * Sun RPC is a product of Sun Microsystems, Inc. and is provided for + * unrestricted use provided that this legend is included on all tape + * media and as a part of the software program in whole or part.  Users + * may copy or modify Sun RPC without charge, but are not authorized + * to license or distribute it to anyone else except as part of a product or + * program developed by the user. + *  + * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE + * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR + * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. + *  + * Sun RPC is provided with no support and without any obligation on the + * part of Sun Microsystems, Inc. to assist in its use, correction, + * modification or enhancement. + *  + * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE + * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC + * OR ANY PART THEREOF. + *  + * In no event will Sun Microsystems, Inc. be liable for any lost revenue + * or profits or other special, indirect and consequential damages, even if + * Sun has been advised of the possibility of such damages. + *  + * Sun Microsystems, Inc. + * 2550 Garcia Avenue + * Mountain View, California  94043 + */ +/* @(#)rpc_parse.h 1.3 87/03/09 (C) 1987 SMI */ + +/* + * rpc_parse.h, Definitions for the RPCL parser  + * Copyright (C) 1987, Sun Microsystems, Inc.  + */ + +enum defkind { +	DEF_CONST, +	DEF_STRUCT, +	DEF_UNION, +	DEF_ENUM, +	DEF_TYPEDEF, +	DEF_PROGRAM +}; +typedef enum defkind defkind; + +typedef char *const_def; + +enum relation { +	REL_VECTOR,	/* fixed length array */ +	REL_ARRAY,	/* variable length array */ +	REL_POINTER,	/* pointer */ +	REL_ALIAS,	/* simple */ +}; +typedef enum relation relation; + +struct typedef_def { +	char *old_prefix; +	char *old_type; +	relation rel; +	char *array_max; +}; +typedef struct typedef_def typedef_def; + + +struct enumval_list { +	char *name; +	char *assignment; +	struct enumval_list *next; +}; +typedef struct enumval_list enumval_list; + +struct enum_def { +	enumval_list *vals; +}; +typedef struct enum_def enum_def; + + +struct declaration { +	char *prefix; +	char *type; +	char *name; +	relation rel; +	char *array_max; +}; +typedef struct declaration declaration; + + +struct decl_list { +	declaration decl; +	struct decl_list *next; +}; +typedef struct decl_list decl_list; + +struct struct_def { +	decl_list *decls; +}; +typedef struct struct_def struct_def; + + +struct case_list { +	char *case_name; +	declaration case_decl; +	struct case_list *next; +}; +typedef struct case_list case_list; + +struct union_def { +	declaration enum_decl; +	case_list *cases; +	declaration *default_decl; +}; +typedef struct union_def union_def; + + + +struct proc_list { +	char *proc_name; +	char *proc_num; +	char *arg_type; +	char *arg_prefix; +	char *res_type; +	char *res_prefix; +	struct proc_list *next; +}; +typedef struct proc_list proc_list; + + +struct version_list { +	char *vers_name; +	char *vers_num; +	proc_list *procs; +	struct version_list *next; +}; +typedef struct version_list version_list; + +struct program_def { +	char *prog_num; +	version_list *versions; +}; +typedef struct program_def program_def; + +struct definition { +	char *def_name; +	defkind def_kind; +	union { +		const_def co; +		struct_def st; +		union_def un; +		enum_def en; +		typedef_def ty; +		program_def pr; +	} def; +}; +typedef struct definition definition; + +/* @(#)rpc_parse.h	2.1 88/08/01 4.0 RPCSRC */ +definition *get_definition(); diff --git a/lib/librpc/rpcgen/rpc_scan.c b/lib/librpc/rpcgen/rpc_scan.c new file mode 100644 index 000000000000..e46a1b5f2b0e --- /dev/null +++ b/lib/librpc/rpcgen/rpc_scan.c @@ -0,0 +1,473 @@ +/* @(#)rpc_scan.c	2.1 88/08/01 4.0 RPCSRC */ +/* + * Sun RPC is a product of Sun Microsystems, Inc. and is provided for + * unrestricted use provided that this legend is included on all tape + * media and as a part of the software program in whole or part.  Users + * may copy or modify Sun RPC without charge, but are not authorized + * to license or distribute it to anyone else except as part of a product or + * program developed by the user. + *  + * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE + * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR + * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. + *  + * Sun RPC is provided with no support and without any obligation on the + * part of Sun Microsystems, Inc. to assist in its use, correction, + * modification or enhancement. + *  + * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE + * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC + * OR ANY PART THEREOF. + *  + * In no event will Sun Microsystems, Inc. be liable for any lost revenue + * or profits or other special, indirect and consequential damages, even if + * Sun has been advised of the possibility of such damages. + *  + * Sun Microsystems, Inc. + * 2550 Garcia Avenue + * Mountain View, California  94043 + */ +#ifndef lint +static char sccsid[] = "@(#)rpc_scan.c 1.6 87/06/24 (C) 1987 SMI"; +#endif + +/* + * rpc_scan.c, Scanner for the RPC protocol compiler  + * Copyright (C) 1987, Sun Microsystems, Inc.  + */ +#include <stdio.h> +#include <ctype.h> +#include <strings.h> +#include "rpc_scan.h" +#include "rpc_util.h" + +#define startcomment(where) (where[0] == '/' && where[1] == '*') +#define endcomment(where) (where[-1] == '*' && where[0] == '/') + +static int pushed = 0;	/* is a token pushed */ +static token lasttok;	/* last token, if pushed */ + +/* + * scan expecting 1 given token  + */ +void +scan(expect, tokp) +	tok_kind expect; +	token *tokp; +{ +	get_token(tokp); +	if (tokp->kind != expect) { +		expected1(expect); +	} +} + +/* + * scan expecting 2 given tokens  + */ +void +scan2(expect1, expect2, tokp) +	tok_kind expect1; +	tok_kind expect2; +	token *tokp; +{ +	get_token(tokp); +	if (tokp->kind != expect1 && tokp->kind != expect2) { +		expected2(expect1, expect2); +	} +} + +/* + * scan expecting 3 given token  + */ +void +scan3(expect1, expect2, expect3, tokp) +	tok_kind expect1; +	tok_kind expect2; +	tok_kind expect3; +	token *tokp; +{ +	get_token(tokp); +	if (tokp->kind != expect1 && tokp->kind != expect2 +	    && tokp->kind != expect3) { +		expected3(expect1, expect2, expect3); +	} +} + + +/* + * scan expecting a constant, possibly symbolic  + */ +void +scan_num(tokp) +	token *tokp; +{ +	get_token(tokp); +	switch (tokp->kind) { +	case TOK_IDENT: +		break; +	default: +		error("constant or identifier expected"); +	} +} + + +/* + * Peek at the next token  + */ +void +peek(tokp) +	token *tokp; +{ +	get_token(tokp); +	unget_token(tokp); +} + + +/* + * Peek at the next token and scan it if it matches what you expect  + */ +int +peekscan(expect, tokp) +	tok_kind expect; +	token *tokp; +{ +	peek(tokp); +	if (tokp->kind == expect) { +		get_token(tokp); +		return (1); +	} +	return (0); +} + + + +/* + * Get the next token, printing out any directive that are encountered.  + */ +void +get_token(tokp) +	token *tokp; +{ +	int commenting; + +	if (pushed) { +		pushed = 0; +		*tokp = lasttok; +		return; +	} +	commenting = 0; +	for (;;) { +		if (*where == 0) { +			for (;;) { +				if (!fgets(curline, MAXLINESIZE, fin)) { +					tokp->kind = TOK_EOF; +					*where = 0; +					return; +				} +				linenum++; +				if (commenting) { +					break; +				} else if (cppline(curline)) { +					docppline(curline, &linenum,  +						  &infilename); +				} else if (directive(curline)) { +					printdirective(curline); +				} else { +					break; +				} +			} +			where = curline; +		} else if (isspace(*where)) { +			while (isspace(*where)) { +				where++;	/* eat */ +			} +		} else if (commenting) { +			where++; +			if (endcomment(where)) { +				where++; +				commenting--; +			} +		} else if (startcomment(where)) { +			where += 2; +			commenting++; +		} else { +			break; +		} +	} + +	/* +	 * 'where' is not whitespace, comment or directive Must be a token!  +	 */ +	switch (*where) { +	case ':': +		tokp->kind = TOK_COLON; +		where++; +		break; +	case ';': +		tokp->kind = TOK_SEMICOLON; +		where++; +		break; +	case ',': +		tokp->kind = TOK_COMMA; +		where++; +		break; +	case '=': +		tokp->kind = TOK_EQUAL; +		where++; +		break; +	case '*': +		tokp->kind = TOK_STAR; +		where++; +		break; +	case '[': +		tokp->kind = TOK_LBRACKET; +		where++; +		break; +	case ']': +		tokp->kind = TOK_RBRACKET; +		where++; +		break; +	case '{': +		tokp->kind = TOK_LBRACE; +		where++; +		break; +	case '}': +		tokp->kind = TOK_RBRACE; +		where++; +		break; +	case '(': +		tokp->kind = TOK_LPAREN; +		where++; +		break; +	case ')': +		tokp->kind = TOK_RPAREN; +		where++; +		break; +	case '<': +		tokp->kind = TOK_LANGLE; +		where++; +		break; +	case '>': +		tokp->kind = TOK_RANGLE; +		where++; +		break; + +	case '"': +		tokp->kind = TOK_STRCONST; +		findstrconst(&where, &tokp->str); +		break; + +	case '-': +	case '0': +	case '1': +	case '2': +	case '3': +	case '4': +	case '5': +	case '6': +	case '7': +	case '8': +	case '9': +		tokp->kind = TOK_IDENT; +		findconst(&where, &tokp->str); +		break; + + +	default: +		if (!(isalpha(*where) || *where == '_')) { +			char buf[100]; +			char *p; + +			s_print(buf, "illegal character in file: "); +			p = buf + strlen(buf); +			if (isprint(*where)) { +				s_print(p, "%c", *where); +			} else { +				s_print(p, "%d", *where); +			} +			error(buf); +		} +		findkind(&where, tokp); +		break; +	} +} + + + +static +unget_token(tokp) +	token *tokp; +{ +	lasttok = *tokp; +	pushed = 1; +} + + +static +findstrconst(str, val) +	char **str; +	char **val; +{ +	char *p; +	int size; + +	p = *str; +	do { +		*p++; +	} while (*p && *p != '"'); +	if (*p == 0) { +		error("unterminated string constant"); +	} +	p++; +	size = p - *str; +	*val = alloc(size + 1); +	(void) strncpy(*val, *str, size); +	(*val)[size] = 0; +	*str = p; +} + +static +findconst(str, val) +	char **str; +	char **val; +{ +	char *p; +	int size; + +	p = *str; +	if (*p == '0' && *(p + 1) == 'x') { +		p++; +		do { +			p++; +		} while (isxdigit(*p)); +	} else { +		do { +			p++; +		} while (isdigit(*p)); +	} +	size = p - *str; +	*val = alloc(size + 1); +	(void) strncpy(*val, *str, size); +	(*val)[size] = 0; +	*str = p; +} + + + +static token symbols[] = { +			  {TOK_CONST, "const"}, +			  {TOK_UNION, "union"}, +			  {TOK_SWITCH, "switch"}, +			  {TOK_CASE, "case"}, +			  {TOK_DEFAULT, "default"}, +			  {TOK_STRUCT, "struct"}, +			  {TOK_TYPEDEF, "typedef"}, +			  {TOK_ENUM, "enum"}, +			  {TOK_OPAQUE, "opaque"}, +			  {TOK_BOOL, "bool"}, +			  {TOK_VOID, "void"}, +			  {TOK_CHAR, "char"}, +			  {TOK_INT, "int"}, +			  {TOK_UNSIGNED, "unsigned"}, +			  {TOK_SHORT, "short"}, +			  {TOK_LONG, "long"}, +			  {TOK_FLOAT, "float"}, +			  {TOK_DOUBLE, "double"}, +			  {TOK_STRING, "string"}, +			  {TOK_PROGRAM, "program"}, +			  {TOK_VERSION, "version"}, +			  {TOK_EOF, "??????"}, +}; + + +static +findkind(mark, tokp) +	char **mark; +	token *tokp; +{ + +	int len; +	token *s; +	char *str; + +	str = *mark; +	for (s = symbols; s->kind != TOK_EOF; s++) { +		len = strlen(s->str); +		if (strncmp(str, s->str, len) == 0) { +			if (!isalnum(str[len]) && str[len] != '_') { +				tokp->kind = s->kind; +				tokp->str = s->str; +				*mark = str + len; +				return; +			} +		} +	} +	tokp->kind = TOK_IDENT; +	for (len = 0; isalnum(str[len]) || str[len] == '_'; len++); +	tokp->str = alloc(len + 1); +	(void) strncpy(tokp->str, str, len); +	tokp->str[len] = 0; +	*mark = str + len; +} + +static +cppline(line) +	char *line; +{ +	return (line == curline && *line == '#'); +} + +static +directive(line) +	char *line; +{ +	return (line == curline && *line == '%'); +} + +static +printdirective(line) +	char *line; +{ +	f_print(fout, "%s", line + 1); +} + +static +docppline(line, lineno, fname) +	char *line; +	int *lineno; +	char **fname; +{ +	char *file; +	int num; +	char *p; + +	line++; +	while (isspace(*line)) { +		line++; +	} +	num = atoi(line); +	while (isdigit(*line)) { +		line++; +	} +	while (isspace(*line)) { +		line++; +	} +	if (*line != '"') { +		error("preprocessor error"); +	} +	line++; +	p = file = alloc(strlen(line) + 1); +	while (*line && *line != '"') { +		*p++ = *line++; +	} +	if (*line == 0) { +		error("preprocessor error"); +	} +	*p = 0; +	if (*file == 0) { +		*fname = NULL; +	} else { +		*fname = file; +	} +	*lineno = num - 1; +} diff --git a/lib/librpc/rpcgen/rpc_scan.h b/lib/librpc/rpcgen/rpc_scan.h new file mode 100644 index 000000000000..ad243d59c152 --- /dev/null +++ b/lib/librpc/rpcgen/rpc_scan.h @@ -0,0 +1,101 @@ +/* @(#)rpc_scan.h	2.1 88/08/01 4.0 RPCSRC */ +/* + * Sun RPC is a product of Sun Microsystems, Inc. and is provided for + * unrestricted use provided that this legend is included on all tape + * media and as a part of the software program in whole or part.  Users + * may copy or modify Sun RPC without charge, but are not authorized + * to license or distribute it to anyone else except as part of a product or + * program developed by the user. + *  + * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE + * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR + * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. + *  + * Sun RPC is provided with no support and without any obligation on the + * part of Sun Microsystems, Inc. to assist in its use, correction, + * modification or enhancement. + *  + * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE + * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC + * OR ANY PART THEREOF. + *  + * In no event will Sun Microsystems, Inc. be liable for any lost revenue + * or profits or other special, indirect and consequential damages, even if + * Sun has been advised of the possibility of such damages. + *  + * Sun Microsystems, Inc. + * 2550 Garcia Avenue + * Mountain View, California  94043 + */ +/* @(#)rpc_scan.h 1.3 87/03/09 (C) 1987 SMI */ + +/* + * rpc_scan.h, Definitions for the RPCL scanner  + * Copyright (C) 1987, Sun Microsystems, Inc.  + */ + +/* + * kinds of tokens  + */ +enum tok_kind { +	TOK_IDENT, +	TOK_STRCONST, +	TOK_LPAREN, +	TOK_RPAREN, +	TOK_LBRACE, +	TOK_RBRACE, +	TOK_LBRACKET, +	TOK_RBRACKET, +	TOK_LANGLE, +	TOK_RANGLE, +	TOK_STAR, +	TOK_COMMA, +	TOK_EQUAL, +	TOK_COLON, +	TOK_SEMICOLON, +	TOK_CONST, +	TOK_STRUCT, +	TOK_UNION, +	TOK_SWITCH, +	TOK_CASE, +	TOK_DEFAULT, +	TOK_ENUM, +	TOK_TYPEDEF, +	TOK_INT, +	TOK_SHORT, +	TOK_LONG, +	TOK_UNSIGNED, +	TOK_FLOAT, +	TOK_DOUBLE, +	TOK_OPAQUE, +	TOK_CHAR, +	TOK_STRING, +	TOK_BOOL, +	TOK_VOID, +	TOK_PROGRAM, +	TOK_VERSION, +	TOK_EOF +}; +typedef enum tok_kind tok_kind; + +/* + * a token  + */ +struct token { +	tok_kind kind; +	char *str; +}; +typedef struct token token; + + +/* + * routine interface  + */ +void scanprint(); +void scan(); +void scan2(); +void scan3(); +void scan_num(); +void peek(); +int peekscan(); +void get_token(); diff --git a/lib/librpc/rpcgen/rpc_svcout.c b/lib/librpc/rpcgen/rpc_svcout.c new file mode 100644 index 000000000000..7289b0da6e1f --- /dev/null +++ b/lib/librpc/rpcgen/rpc_svcout.c @@ -0,0 +1,275 @@ +/* @(#)rpc_svcout.c	2.1 88/08/01 4.0 RPCSRC */ +/* + * Sun RPC is a product of Sun Microsystems, Inc. and is provided for + * unrestricted use provided that this legend is included on all tape + * media and as a part of the software program in whole or part.  Users + * may copy or modify Sun RPC without charge, but are not authorized + * to license or distribute it to anyone else except as part of a product or + * program developed by the user. + *  + * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE + * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR + * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. + *  + * Sun RPC is provided with no support and without any obligation on the + * part of Sun Microsystems, Inc. to assist in its use, correction, + * modification or enhancement. + *  + * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE + * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC + * OR ANY PART THEREOF. + *  + * In no event will Sun Microsystems, Inc. be liable for any lost revenue + * or profits or other special, indirect and consequential damages, even if + * Sun has been advised of the possibility of such damages. + *  + * Sun Microsystems, Inc. + * 2550 Garcia Avenue + * Mountain View, California  94043 + */ +#ifndef lint +static char sccsid[] = "@(#)rpc_svcout.c 1.6 87/06/24 (C) 1987 SMI"; +#endif + +/* + * rpc_svcout.c, Server-skeleton outputter for the RPC protocol compiler + * Copyright (C) 1987, Sun Microsytsems, Inc.  + */ +#include <stdio.h> +#include <strings.h> +#include "rpc_parse.h" +#include "rpc_util.h" + +static char RQSTP[] = "rqstp"; +static char TRANSP[] = "transp"; +static char ARG[] = "argument"; +static char RESULT[] = "result"; +static char ROUTINE[] = "local"; + + +/* + * write most of the service, that is, everything but the registrations.  + */ +void +write_most() +{ +	list *l; +	definition *def; +	version_list *vp; + +	for (l = defined; l != NULL; l = l->next) { +		def = (definition *) l->val; +		if (def->def_kind == DEF_PROGRAM) { +			for (vp = def->def.pr.versions; vp != NULL; vp = vp->next) { +				f_print(fout, "\nstatic void "); +				pvname(def->def_name, vp->vers_num); +				f_print(fout, "();"); +			} +		} +	} +	f_print(fout, "\n\n"); +	f_print(fout, "main()\n"); +	f_print(fout, "{\n"); +	f_print(fout, "\tSVCXPRT *%s;\n", TRANSP); +	f_print(fout, "\n"); +	for (l = defined; l != NULL; l = l->next) { +		def = (definition *) l->val; +		if (def->def_kind != DEF_PROGRAM) { +			continue; +		} +		for (vp = def->def.pr.versions; vp != NULL; vp = vp->next) { + 			f_print(fout, "\t(void)pmap_unset(%s, %s);\n", def->def_name, vp->vers_name); +		} +	} +} + + +/* + * write a registration for the given transport  + */ +void +write_register(transp) +	char *transp; +{ +	list *l; +	definition *def; +	version_list *vp; + +	f_print(fout, "\n"); +	f_print(fout, "\t%s = svc%s_create(RPC_ANYSOCK", TRANSP, transp); +	if (streq(transp, "tcp")) { +		f_print(fout, ", 0, 0"); +	} +	f_print(fout, ");\n"); +	f_print(fout, "\tif (%s == NULL) {\n", TRANSP); + 	f_print(fout, "\t\t(void)fprintf(stderr, \"cannot create %s service.\\n\");\n", transp); +	f_print(fout, "\t\texit(1);\n"); +	f_print(fout, "\t}\n"); + +	for (l = defined; l != NULL; l = l->next) { +		def = (definition *) l->val; +		if (def->def_kind != DEF_PROGRAM) { +			continue; +		} +		for (vp = def->def.pr.versions; vp != NULL; vp = vp->next) { +			f_print(fout, +				"\tif (!svc_register(%s, %s, %s, ", +				TRANSP, def->def_name, vp->vers_name); +			pvname(def->def_name, vp->vers_num); +			f_print(fout, ", IPPROTO_%s)) {\n", +				streq(transp, "udp") ? "UDP" : "TCP"); +			f_print(fout, + 				"\t\t(void)fprintf(stderr, \"unable to register (%s, %s, %s).\\n\");\n", +				def->def_name, vp->vers_name, transp); +			f_print(fout, "\t\texit(1);\n"); +			f_print(fout, "\t}\n"); +		} +	} +} + + +/* + * write the rest of the service  + */ +void +write_rest() +{ +	f_print(fout, "\tsvc_run();\n"); + 	f_print(fout, "\t(void)fprintf(stderr, \"svc_run returned\\n\");\n"); +	f_print(fout, "\texit(1);\n"); +	f_print(fout, "}\n"); +} + +void +write_programs(storage) +	char *storage; +{ +	list *l; +	definition *def; + +	for (l = defined; l != NULL; l = l->next) { +		def = (definition *) l->val; +		if (def->def_kind == DEF_PROGRAM) { +			write_program(def, storage); +		} +	} +} + + +static +write_program(def, storage) +	definition *def; +	char *storage; +{ +	version_list *vp; +	proc_list *proc; +	int filled; + +	for (vp = def->def.pr.versions; vp != NULL; vp = vp->next) { +		f_print(fout, "\n"); +		if (storage != NULL) { +			f_print(fout, "%s ", storage); +		} +		f_print(fout, "void\n"); +		pvname(def->def_name, vp->vers_num); +		f_print(fout, "(%s, %s)\n", RQSTP, TRANSP); +		f_print(fout, "	struct svc_req *%s;\n", RQSTP); +		f_print(fout, "	SVCXPRT *%s;\n", TRANSP); +		f_print(fout, "{\n"); + +		filled = 0; +		f_print(fout, "\tunion {\n"); +		for (proc = vp->procs; proc != NULL; proc = proc->next) { +			if (streq(proc->arg_type, "void")) { +				continue; +			} +			filled = 1; +			f_print(fout, "\t\t"); +			ptype(proc->arg_prefix, proc->arg_type, 0); +			pvname(proc->proc_name, vp->vers_num); +			f_print(fout, "_arg;\n"); +		} +		if (!filled) { +			f_print(fout, "\t\tint fill;\n"); +		} +		f_print(fout, "\t} %s;\n", ARG); +		f_print(fout, "\tchar *%s;\n", RESULT); +		f_print(fout, "\tbool_t (*xdr_%s)(), (*xdr_%s)();\n", ARG, RESULT); +		f_print(fout, "\tchar *(*%s)();\n", ROUTINE); +		f_print(fout, "\n"); +		f_print(fout, "\tswitch (%s->rq_proc) {\n", RQSTP); + +		if (!nullproc(vp->procs)) { +			f_print(fout, "\tcase NULLPROC:\n"); + 			f_print(fout, "\t\t(void)svc_sendreply(%s, xdr_void, (char *)NULL);\n", TRANSP); +			f_print(fout, "\t\treturn;\n\n"); +		} +		for (proc = vp->procs; proc != NULL; proc = proc->next) { +			f_print(fout, "\tcase %s:\n", proc->proc_name); +			f_print(fout, "\t\txdr_%s = xdr_%s;\n", ARG,  +				stringfix(proc->arg_type)); +			f_print(fout, "\t\txdr_%s = xdr_%s;\n", RESULT,  +				stringfix(proc->res_type)); +			f_print(fout, "\t\t%s = (char *(*)()) ", ROUTINE); +			pvname(proc->proc_name, vp->vers_num); +			f_print(fout, ";\n"); +			f_print(fout, "\t\tbreak;\n\n"); +		} +		f_print(fout, "\tdefault:\n"); +		printerr("noproc", TRANSP); +		f_print(fout, "\t\treturn;\n"); +		f_print(fout, "\t}\n"); + + 		f_print(fout, "\tbzero((char *)&%s, sizeof(%s));\n", ARG, ARG); +		printif("getargs", TRANSP, "&", ARG); +		printerr("decode", TRANSP); +		f_print(fout, "\t\treturn;\n"); +		f_print(fout, "\t}\n"); + +		f_print(fout, "\t%s = (*%s)(&%s, %s);\n", RESULT, ROUTINE, ARG, +			RQSTP); +		f_print(fout,  +			"\tif (%s != NULL && !svc_sendreply(%s, xdr_%s, %s)) {\n", +			RESULT, TRANSP, RESULT, RESULT); +		printerr("systemerr", TRANSP); +		f_print(fout, "\t}\n"); + +		printif("freeargs", TRANSP, "&", ARG); + 		f_print(fout, "\t\t(void)fprintf(stderr, \"unable to free arguments\\n\");\n"); +		f_print(fout, "\t\texit(1);\n"); +		f_print(fout, "\t}\n"); + +		f_print(fout, "}\n\n"); +	} +} + +static +printerr(err, transp) +	char *err; +	char *transp; +{ +	f_print(fout, "\t\tsvcerr_%s(%s);\n", err, transp); +} + +static +printif(proc, transp, prefix, arg) +	char *proc; +	char *transp; +	char *prefix; +	char *arg; +{ +	f_print(fout, "\tif (!svc_%s(%s, xdr_%s, %s%s)) {\n", +		proc, transp, arg, prefix, arg); +} + + +nullproc(proc) +	proc_list *proc; +{ +	for (; proc != NULL; proc = proc->next) { +		if (streq(proc->proc_num, "0")) { +			return (1); +		} +	} +	return (0); +} diff --git a/lib/librpc/rpcgen/rpc_util.c b/lib/librpc/rpcgen/rpc_util.c new file mode 100644 index 000000000000..8136535b2f9d --- /dev/null +++ b/lib/librpc/rpcgen/rpc_util.c @@ -0,0 +1,436 @@ +/* @(#)rpc_util.c	2.1 88/08/01 4.0 RPCSRC */ +/* + * Sun RPC is a product of Sun Microsystems, Inc. and is provided for + * unrestricted use provided that this legend is included on all tape + * media and as a part of the software program in whole or part.  Users + * may copy or modify Sun RPC without charge, but are not authorized + * to license or distribute it to anyone else except as part of a product or + * program developed by the user. + *  + * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE + * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR + * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. + *  + * Sun RPC is provided with no support and without any obligation on the + * part of Sun Microsystems, Inc. to assist in its use, correction, + * modification or enhancement. + *  + * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE + * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC + * OR ANY PART THEREOF. + *  + * In no event will Sun Microsystems, Inc. be liable for any lost revenue + * or profits or other special, indirect and consequential damages, even if + * Sun has been advised of the possibility of such damages. + *  + * Sun Microsystems, Inc. + * 2550 Garcia Avenue + * Mountain View, California  94043 + */ +#ifndef lint +static char sccsid[] = "@(#)rpc_util.c 1.5 87/06/24 (C) 1987 SMI"; +#endif + +/* + * rpc_util.c, Utility routines for the RPC protocol compiler  + * Copyright (C) 1987, Sun Microsystems, Inc.  + */ +#include <stdio.h> +#include "rpc_scan.h" +#include "rpc_parse.h" +#include "rpc_util.h" + +char curline[MAXLINESIZE];	/* current read line */ +char *where = curline;	/* current point in line */ +int linenum = 0;	/* current line number */ + +char *infilename;	/* input filename */ + +#define NFILES 4 +char *outfiles[NFILES];	/* output file names */ +int nfiles; + +FILE *fout;	/* file pointer of current output */ +FILE *fin;	/* file pointer of current input */ + +list *defined;	/* list of defined things */ + +/* + * Reinitialize the world  + */ +reinitialize() +{ +	bzero(curline, MAXLINESIZE); +	where = curline; +	linenum = 0; +	defined = NULL; +} + +/* + * string equality  + */ +streq(a, b) +	char *a; +	char *b; +{ +	return (strcmp(a, b) == 0); +} + +/* + * find a value in a list  + */ +char * +findval(lst, val, cmp) +	list *lst; +	char *val; +	int (*cmp) (); + +{ +	for (; lst != NULL; lst = lst->next) { +		if ((*cmp) (lst->val, val)) { +			return (lst->val); +		} +	} +	return (NULL); +} + +/* + * store a value in a list  + */ +void +storeval(lstp, val) +	list **lstp; +	char *val; +{ +	list **l; +	list *lst; + +	for (l = lstp; *l != NULL; l = (list **) & (*l)->next); +	lst = ALLOC(list); +	lst->val = val; +	lst->next = NULL; +	*l = lst; +} + + +static +findit(def, type) +	definition *def; +	char *type; +{ +	return (streq(def->def_name, type)); +} + + +static char * +fixit(type, orig) +	char *type; +	char *orig; +{ +	definition *def; + +	def = (definition *) FINDVAL(defined, type, findit); +	if (def == NULL || def->def_kind != DEF_TYPEDEF) { +		return (orig); +	} +	switch (def->def.ty.rel) { +	case REL_VECTOR: +		return (def->def.ty.old_type); +	case REL_ALIAS: +		return (fixit(def->def.ty.old_type, orig)); +	default: +		return (orig); +	} +} + +char * +fixtype(type) +	char *type; +{ +	return (fixit(type, type)); +} + +char * +stringfix(type) +	char *type; +{ +	if (streq(type, "string")) { +		return ("wrapstring"); +	} else { +		return (type); +	} +} + +void +ptype(prefix, type, follow) +	char *prefix; +	char *type; +	int follow; +{ +	if (prefix != NULL) { +		if (streq(prefix, "enum")) { +			f_print(fout, "enum "); +		} else { +			f_print(fout, "struct "); +		} +	} +	if (streq(type, "bool")) { +		f_print(fout, "bool_t "); +	} else if (streq(type, "string")) { +		f_print(fout, "char *"); +	} else { +		f_print(fout, "%s ", follow ? fixtype(type) : type); +	} +} + + +static +typedefed(def, type) +	definition *def; +	char *type; +{ +	if (def->def_kind != DEF_TYPEDEF || def->def.ty.old_prefix != NULL) { +		return (0); +	} else { +		return (streq(def->def_name, type)); +	} +} + +isvectordef(type, rel) +	char *type; +	relation rel; +{ +	definition *def; + +	for (;;) { +		switch (rel) { +		case REL_VECTOR: +			return (!streq(type, "string")); +		case REL_ARRAY: +			return (0); +		case REL_POINTER: +			return (0); +		case REL_ALIAS: +			def = (definition *) FINDVAL(defined, type, typedefed); +			if (def == NULL) { +				return (0); +			} +			type = def->def.ty.old_type; +			rel = def->def.ty.rel; +		} +	} +} + + +static char * +locase(str) +	char *str; +{ +	char c; +	static char buf[100]; +	char *p = buf; + +	while (c = *str++) { +		*p++ = (c >= 'A' && c <= 'Z') ? (c - 'A' + 'a') : c; +	} +	*p = 0; +	return (buf); +} + + +void +pvname(pname, vnum) +	char *pname; +	char *vnum; +{ +	f_print(fout, "%s_%s", locase(pname), vnum); +} + + +/* + * print a useful (?) error message, and then die  + */ +void +error(msg) +	char *msg; +{ +	printwhere(); +	f_print(stderr, "%s, line %d: ", infilename, linenum); +	f_print(stderr, "%s\n", msg); +	crash(); +} + +/* + * Something went wrong, unlink any files that we may have created and then + * die.  + */ +crash() +{ +	int i; + +	for (i = 0; i < nfiles; i++) { +		(void) unlink(outfiles[i]); +	} +	exit(1); +} + + +void +record_open(file) +	char *file; +{ +	if (nfiles < NFILES) { +		outfiles[nfiles++] = file; +	} else { +		f_print(stderr, "too many files!\n"); +		crash(); +	} +} + +static char expectbuf[100]; +static char *toktostr(); + +/* + * error, token encountered was not the expected one  + */ +void +expected1(exp1) +	tok_kind exp1; +{ +	s_print(expectbuf, "expected '%s'", +		toktostr(exp1)); +	error(expectbuf); +} + +/* + * error, token encountered was not one of two expected ones  + */ +void +expected2(exp1, exp2) +	tok_kind exp1, exp2; +{ +	s_print(expectbuf, "expected '%s' or '%s'", +		toktostr(exp1), +		toktostr(exp2)); +	error(expectbuf); +} + +/* + * error, token encountered was not one of 3 expected ones  + */ +void +expected3(exp1, exp2, exp3) +	tok_kind exp1, exp2, exp3; +{ +	s_print(expectbuf, "expected '%s', '%s' or '%s'", +		toktostr(exp1), +		toktostr(exp2), +		toktostr(exp3)); +	error(expectbuf); +} + +void +tabify(f, tab) +	FILE *f; +	int tab; +{ +	while (tab--) { +		(void) fputc('\t', f); +	} +} + + + +static token tokstrings[] = { +			     {TOK_IDENT, "identifier"}, +			     {TOK_CONST, "const"}, +			     {TOK_RPAREN, ")"}, +			     {TOK_LPAREN, "("}, +			     {TOK_RBRACE, "}"}, +			     {TOK_LBRACE, "{"}, +			     {TOK_LBRACKET, "["}, +			     {TOK_RBRACKET, "]"}, +			     {TOK_STAR, "*"}, +			     {TOK_COMMA, ","}, +			     {TOK_EQUAL, "="}, +			     {TOK_COLON, ":"}, +			     {TOK_SEMICOLON, ";"}, +			     {TOK_UNION, "union"}, +			     {TOK_STRUCT, "struct"}, +			     {TOK_SWITCH, "switch"}, +			     {TOK_CASE, "case"}, +			     {TOK_DEFAULT, "default"}, +			     {TOK_ENUM, "enum"}, +			     {TOK_TYPEDEF, "typedef"}, +			     {TOK_INT, "int"}, +			     {TOK_SHORT, "short"}, +			     {TOK_LONG, "long"}, +			     {TOK_UNSIGNED, "unsigned"}, +			     {TOK_DOUBLE, "double"}, +			     {TOK_FLOAT, "float"}, +			     {TOK_CHAR, "char"}, +			     {TOK_STRING, "string"}, +			     {TOK_OPAQUE, "opaque"}, +			     {TOK_BOOL, "bool"}, +			     {TOK_VOID, "void"}, +			     {TOK_PROGRAM, "program"}, +			     {TOK_VERSION, "version"}, +			     {TOK_EOF, "??????"} +}; + +static char * +toktostr(kind) +	tok_kind kind; +{ +	token *sp; + +	for (sp = tokstrings; sp->kind != TOK_EOF && sp->kind != kind; sp++); +	return (sp->str); +} + + + +static +printbuf() +{ +	char c; +	int i; +	int cnt; + +#	define TABSIZE 4 + +	for (i = 0; c = curline[i]; i++) { +		if (c == '\t') { +			cnt = 8 - (i % TABSIZE); +			c = ' '; +		} else { +			cnt = 1; +		} +		while (cnt--) { +			(void) fputc(c, stderr); +		} +	} +} + + +static +printwhere() +{ +	int i; +	char c; +	int cnt; + +	printbuf(); +	for (i = 0; i < where - curline; i++) { +		c = curline[i]; +		if (c == '\t') { +			cnt = 8 - (i % TABSIZE); +		} else { +			cnt = 1; +		} +		while (cnt--) { +			(void) fputc('^', stderr); +		} +	} +	(void) fputc('\n', stderr); +} diff --git a/lib/librpc/rpcgen/rpc_util.h b/lib/librpc/rpcgen/rpc_util.h new file mode 100644 index 000000000000..f4525a04410f --- /dev/null +++ b/lib/librpc/rpcgen/rpc_util.h @@ -0,0 +1,114 @@ +/* @(#)rpc_util.h	2.1 88/08/01 4.0 RPCSRC */ +/* + * Sun RPC is a product of Sun Microsystems, Inc. and is provided for + * unrestricted use provided that this legend is included on all tape + * media and as a part of the software program in whole or part.  Users + * may copy or modify Sun RPC without charge, but are not authorized + * to license or distribute it to anyone else except as part of a product or + * program developed by the user. + *  + * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE + * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR + * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. + *  + * Sun RPC is provided with no support and without any obligation on the + * part of Sun Microsystems, Inc. to assist in its use, correction, + * modification or enhancement. + *  + * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE + * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC + * OR ANY PART THEREOF. + *  + * In no event will Sun Microsystems, Inc. be liable for any lost revenue + * or profits or other special, indirect and consequential damages, even if + * Sun has been advised of the possibility of such damages. + *  + * Sun Microsystems, Inc. + * 2550 Garcia Avenue + * Mountain View, California  94043 + */ +/* @(#)rpc_util.h 1.6 87/06/24 (C) 1987 SMI */ + +/* + * rpc_util.h, Useful definitions for the RPC protocol compiler  + * Copyright (C) 1987, Sun Microsystems, Inc.  + */ +extern char *malloc(); + +#define alloc(size)		malloc((unsigned)(size)) +#define ALLOC(object)   (object *) malloc(sizeof(object)) + +extern char *sprintf(); + +#define s_print	(void) sprintf +#define f_print (void) fprintf + +struct list { +	char *val; +	struct list *next; +}; +typedef struct list list; + +/* + * Global variables  + */ +#define MAXLINESIZE 1024 +extern char curline[MAXLINESIZE]; +extern char *where; +extern int linenum; + +extern char *infilename; +extern FILE *fout; +extern FILE *fin; + +extern list *defined; + +/* + * rpc_util routines  + */ +void storeval(); + +#define STOREVAL(list,item)	\ +	storeval(list,(char *)item) + +char *findval(); + +#define FINDVAL(list,item,finder) \ +	findval(list, (char *) item, finder) + +char *fixtype(); +char *stringfix(); +void pvname(); +void ptype(); +int isvectordef(); +int streq(); +void error(); +void expected1(); +void expected2(); +void expected3(); +void tabify(); +void record_open(); + +/* + * rpc_cout routines  + */ +void cprint(); +void emit(); + +/* + * rpc_hout routines  + */ +void print_datadef(); + +/* + * rpc_svcout routines  + */ +void write_most(); +void write_register(); +void write_rest(); +void write_programs(); + +/* + * rpc_clntout routines + */ +void write_stubs(); diff --git a/lib/librpc/rpcsvc/Makefile b/lib/librpc/rpcsvc/Makefile new file mode 100644 index 000000000000..690d945d5e54 --- /dev/null +++ b/lib/librpc/rpcsvc/Makefile @@ -0,0 +1,80 @@ +# +# @(#)Makefile	2.3 88/08/11 4.0 RPCSRC +# +# +RPCCOM = rpcgen +LIB = -lrpclib + +DESTDIR= +CFLAGS= -O +LDFLAGS= + +HDRS= klm_prot.h mount.h nfs_prot.h nlm_prot.h rex.h rquota.h rnusers.h\ +      rquota.h rstat.h sm_inter.h spray.h yppasswd.h yp.h +XFILES= bootparam_prot.x klm_prot.x mount.x nfs_prot.x nlm_prot.x \ +      rex.x rnusers.x rquota.x rstat.x sm_inter.x spray.x yppasswd.x yp.x +BIN= rstat +SVCBIN= rstat_svc +GEN= rstat_clnt.c rstat_svc.c rstat_xdr.c + +all:	$(HDRS) $(BIN) $(SVCBIN) + +install: $(HDRS) $(XFILES) +	@echo "Creating RPC service headers directory" +	-mkdir ${DESTDIR}/usr/include/rpcsvc && \ +		chown bin ${DESTDIR}/usr/include/rpcsvc && \ +		chmod 755 ${DESTDIR}/usr/include/rpcsvc +	@echo "Installing RPC service header and definition files" +	for i in $(HDRS) $(XFILES); do \ +		(install -c -m 644 $$i ${DESTDIR}/usr/include/rpcsvc) done +	-mkdir ${DESTDIR}/etc && chown bin ${DESTDIR}/etc && \ +		chmod 755 ${DESTDIR}/etc +	@echo "Installing ${SVCBIN} in ${DESTDIR}/etc" +	@set -x;for i in ${SVCBIN}; do \ +		(install -c -s $$i ${DESTDIR}/etc/$$i); done +	@echo "Installing ${BIN} in ${DESTDIR}/usr/bin" +	@set -x;for i in ${BIN}; do \ +		(install -c -s $$i ${DESTDIR}/usr/bin/$$i); done + +rstat_svc: rstat_proc.o rstat_svc.o rstat_xdr.o +	$(CC) $(LDFLAGS) -o $@ rstat_proc.o rstat_svc.o rstat_xdr.o $(LIB) + +rstat: rstat.o rstat_clnt.o rstat_xdr.o +	$(CC) $(LDFLAGS) -o $@ rstat.o rstat_clnt.o rstat_xdr.o $(LIB) + +rstat.c rstat_proc.c:	rstat.h + +klm_prot.h:	klm_prot.x +	$(RPCCOM) -h klm_prot.x -o $@ +mount.h:	mount.x +	$(RPCCOM) -h mount.x -o $@ +nfs_prot.h:	nfs_prot.x +	$(RPCCOM) -h nfs_prot.x -o $@ +nlm_prot.h:	nlm_prot.x +	$(RPCCOM) -h nlm_prot.x -o $@ +rex.h:	rex.x +	$(RPCCOM) -h rex.x -o $@ +rnusers.h:	rnusers.x +	$(RPCCOM) -h rnusers.x -o $@ +rquota.h:	rquota.x +	$(RPCCOM) -h rquota.x -o $@ +rstat.h:	rstat.x +	$(RPCCOM) -h rstat.x -o $@ +sm_inter.h:	sm_inter.x +	$(RPCCOM) -h sm_inter.x -o $@ +spray.h:	spray.x +	$(RPCCOM) -h spray.x -o $@ +yp.h:	yp.x +	$(RPCCOM) -h yp.x -o $@ +yppasswd.h:	yppasswd.x +	$(RPCCOM) -h yppasswd.x -o $@ + +rstat_clnt.c:	rstat.x +	$(RPCCOM) -l rstat.x -o $@ +rstat_svc.c:	rstat.x +	$(RPCCOM) -s udp rstat.x -o $@ +rstat_xdr.c:	rstat.x +	$(RPCCOM) -c rstat.x -o $@ + +clean cleanup: +	rm -f *.o $(GEN) $(BIN) $(SVCBIN) diff --git a/lib/librpc/rpcsvc/bootparam_prot.x b/lib/librpc/rpcsvc/bootparam_prot.x new file mode 100644 index 000000000000..65bc0dcbfb2a --- /dev/null +++ b/lib/librpc/rpcsvc/bootparam_prot.x @@ -0,0 +1,97 @@ +/* @(#)bootparam_prot.x	2.1 88/08/01 4.0 RPCSRC */ +/* @(#)bootparam_prot.x 1.2 87/06/24 Copyr 1987 Sun Micro */ + +/* + * Sun RPC is a product of Sun Microsystems, Inc. and is provided for + * unrestricted use provided that this legend is included on all tape + * media and as a part of the software program in whole or part.  Users + * may copy or modify Sun RPC without charge, but are not authorized + * to license or distribute it to anyone else except as part of a product or + * program developed by the user. + *  + * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE + * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR + * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. + *  + * Sun RPC is provided with no support and without any obligation on the + * part of Sun Microsystems, Inc. to assist in its use, correction, + * modification or enhancement. + *  + * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE + * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC + * OR ANY PART THEREOF. + *  + * In no event will Sun Microsystems, Inc. be liable for any lost revenue + * or profits or other special, indirect and consequential damages, even if + * Sun has been advised of the possibility of such damages. + *  + * Sun Microsystems, Inc. + * 2550 Garcia Avenue + * Mountain View, California  94043 + */ + +/* + * RPC for bootparms service. + * There are two procedures: + *   WHOAMI takes a net address and returns a client name and also a + *	likely net address for routing + *   GETFILE takes a client name and file identifier and returns the + *	server name, server net address and pathname for the file. + *   file identifiers typically include root, swap, pub and dump + */ + +#ifdef RPC_HDR +%#include <rpc/types.h> +%#include <sys/time.h> +%#include <sys/errno.h> +%#include <nfs/nfs.h> +#endif + +const MAX_MACHINE_NAME  = 255; +const MAX_PATH_LEN	= 1024; +const MAX_FILEID	= 32; +const IP_ADDR_TYPE	= 1; + +typedef	string	bp_machine_name_t<MAX_MACHINE_NAME>; +typedef	string	bp_path_t<MAX_PATH_LEN>; +typedef	string	bp_fileid_t<MAX_FILEID>; + +struct	ip_addr_t { +	char	net; +	char	host; +	char	lh; +	char	impno; +}; + +union bp_address switch (int address_type) { +	case IP_ADDR_TYPE: +		ip_addr_t	ip_addr; +}; + +struct bp_whoami_arg { +	bp_address		client_address; +}; + +struct bp_whoami_res { +	bp_machine_name_t	client_name; +	bp_machine_name_t	domain_name; +	bp_address		router_address; +}; + +struct bp_getfile_arg { +	bp_machine_name_t	client_name; +	bp_fileid_t		file_id; +}; +	 +struct bp_getfile_res { +	bp_machine_name_t	server_name; +	bp_address		server_address; +	bp_path_t		server_path; +}; + +program BOOTPARAMPROG { +	version BOOTPARAMVERS { +		bp_whoami_res	BOOTPARAMPROC_WHOAMI(bp_whoami_arg) = 1; +		bp_getfile_res	BOOTPARAMPROC_GETFILE(bp_getfile_arg) = 2; +	} = 1; +} = 100026; diff --git a/lib/librpc/rpcsvc/klm_prot.x b/lib/librpc/rpcsvc/klm_prot.x new file mode 100644 index 000000000000..e23caf40f743 --- /dev/null +++ b/lib/librpc/rpcsvc/klm_prot.x @@ -0,0 +1,132 @@ +/* @(#)klm_prot.x	2.1 88/08/01 4.0 RPCSRC */ +/* @(#)klm_prot.x 1.7 87/07/08 Copyr 1987 Sun Micro */ + +/* + * Sun RPC is a product of Sun Microsystems, Inc. and is provided for + * unrestricted use provided that this legend is included on all tape + * media and as a part of the software program in whole or part.  Users + * may copy or modify Sun RPC without charge, but are not authorized + * to license or distribute it to anyone else except as part of a product or + * program developed by the user. + *  + * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE + * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR + * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. + *  + * Sun RPC is provided with no support and without any obligation on the + * part of Sun Microsystems, Inc. to assist in its use, correction, + * modification or enhancement. + *  + * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE + * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC + * OR ANY PART THEREOF. + *  + * In no event will Sun Microsystems, Inc. be liable for any lost revenue + * or profits or other special, indirect and consequential damages, even if + * Sun has been advised of the possibility of such damages. + *  + * Sun Microsystems, Inc. + * 2550 Garcia Avenue + * Mountain View, California  94043 + */ + +/* + * Kernel/lock manager protocol definition + * Copyright (C) 1986 Sun Microsystems, Inc. + * + * protocol used between the UNIX kernel (the "client") and the + * local lock manager.  The local lock manager is a deamon running + * above the kernel. + */ +program KLM_PROG { +	version KLM_VERS { + +		klm_testrply	KLM_TEST (struct klm_testargs) =	1; + +		klm_stat	KLM_LOCK (struct klm_lockargs) =	2; + +		klm_stat	KLM_CANCEL (struct klm_lockargs) =	3; +		/* klm_granted=> the cancel request fails due to lock is already granted */ +		/* klm_denied=> the cancel request successfully aborts +lock request  */ + +		klm_stat	KLM_UNLOCK (struct klm_unlockargs) =	4; +	} = 1; +} = 100020; + +const	LM_MAXSTRLEN = 1024; + +/* + * lock manager status returns + */ +enum klm_stats { +	klm_granted = 0,	/* lock is granted */ +	klm_denied = 1,		/* lock is denied */ +	klm_denied_nolocks = 2, /* no lock entry available */ +	klm_working = 3 	/* lock is being processed */ +}; + +/* + * lock manager lock identifier + */ +struct klm_lock { +	string server_name<LM_MAXSTRLEN>; +	netobj fh;		/* a counted file handle */ +	int pid;		/* holder of the lock */ +	unsigned l_offset;	/* beginning offset of the lock */ +	unsigned l_len;		/* byte length of the lock; +				 * zero means through end of file */ +}; + +/* + * lock holder identifier + */ +struct klm_holder { +	bool exclusive;		/* FALSE if shared lock */ +	int svid;		/* holder of the lock (pid) */ +	unsigned l_offset;	/* beginning offset of the lock */ +	unsigned l_len;		/* byte length of the lock; +				 * zero means through end of file */ +}; + +/* + * reply to KLM_LOCK / KLM_UNLOCK / KLM_CANCEL + */ +struct klm_stat { +	klm_stats stat; +}; + +/* + * reply to a KLM_TEST call + */ +union klm_testrply switch (klm_stats stat) { +	case klm_denied: +		struct klm_holder holder; +	default: /* All other cases return no arguments */ +		void; +}; + + +/* + * arguments to KLM_LOCK + */ +struct klm_lockargs { +	bool block; +	bool exclusive; +	struct klm_lock alock; +}; + +/* + * arguments to KLM_TEST + */ +struct klm_testargs { +	bool exclusive; +	struct klm_lock alock; +}; + +/* + * arguments to KLM_UNLOCK + */ +struct klm_unlockargs { +	struct klm_lock alock; +}; diff --git a/lib/librpc/rpcsvc/mount.x b/lib/librpc/rpcsvc/mount.x new file mode 100644 index 000000000000..7e0d7f3ad6d9 --- /dev/null +++ b/lib/librpc/rpcsvc/mount.x @@ -0,0 +1,161 @@ +/* @(#)mount.x	2.1 88/08/01 4.0 RPCSRC */ +/* @(#)mount.x 1.2 87/09/18 Copyr 1987 Sun Micro */ + +/* + * Sun RPC is a product of Sun Microsystems, Inc. and is provided for + * unrestricted use provided that this legend is included on all tape + * media and as a part of the software program in whole or part.  Users + * may copy or modify Sun RPC without charge, but are not authorized + * to license or distribute it to anyone else except as part of a product or + * program developed by the user. + *  + * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE + * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR + * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. + *  + * Sun RPC is provided with no support and without any obligation on the + * part of Sun Microsystems, Inc. to assist in its use, correction, + * modification or enhancement. + *  + * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE + * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC + * OR ANY PART THEREOF. + *  + * In no event will Sun Microsystems, Inc. be liable for any lost revenue + * or profits or other special, indirect and consequential damages, even if + * Sun has been advised of the possibility of such damages. + *  + * Sun Microsystems, Inc. + * 2550 Garcia Avenue + * Mountain View, California  94043 + */ + +/* + * Protocol description for the mount program + */ + + +const MNTPATHLEN = 1024;	/* maximum bytes in a pathname argument */ +const MNTNAMLEN = 255;		/* maximum bytes in a name argument */ +const FHSIZE = 32;		/* size in bytes of a file handle */ + +/* + * The fhandle is the file handle that the server passes to the client. + * All file operations are done using the file handles to refer to a file + * or a directory. The file handle can contain whatever information the + * server needs to distinguish an individual file. + */ +typedef opaque fhandle[FHSIZE];	 + +/* + * If a status of zero is returned, the call completed successfully, and  + * a file handle for the directory follows. A non-zero status indicates + * some sort of error. The status corresponds with UNIX error numbers. + */ +union fhstatus switch (unsigned fhs_status) { +case 0: +	fhandle fhs_fhandle; +default: +	void; +}; + +/* + * The type dirpath is the pathname of a directory + */ +typedef string dirpath<MNTPATHLEN>; + +/* + * The type name is used for arbitrary names (hostnames, groupnames) + */ +typedef string name<MNTNAMLEN>; + +/* + * A list of who has what mounted + */ +typedef struct mountbody *mountlist; +struct mountbody { +	name ml_hostname; +	dirpath ml_directory; +	mountlist ml_next; +}; + +/* + * A list of netgroups + */ +typedef struct groupnode *groups; +struct groupnode { +	name gr_name; +	groups gr_next; +}; + +/* + * A list of what is exported and to whom + */ +typedef struct exportnode *exports; +struct exportnode { +	dirpath ex_dir; +	groups ex_groups; +	exports ex_next; +}; + +program MOUNTPROG { +	/* +	 * Version one of the mount protocol communicates with version two +	 * of the NFS protocol. The only connecting point is the fhandle  +	 * structure, which is the same for both protocols. +	 */ +	version MOUNTVERS { +		/* +		 * Does no work. It is made available in all RPC services +		 * to allow server reponse testing and timing +		 */ +		void +		MOUNTPROC_NULL(void) = 0; + +		/*	 +		 * If fhs_status is 0, then fhs_fhandle contains the +	 	 * file handle for the directory. This file handle may +		 * be used in the NFS protocol. This procedure also adds +		 * a new entry to the mount list for this client mounting +		 * the directory. +		 * Unix authentication required. +		 */ +		fhstatus  +		MOUNTPROC_MNT(dirpath) = 1; + +		/* +		 * Returns the list of remotely mounted filesystems. The  +		 * mountlist contains one entry for each hostname and  +		 * directory pair. +		 */ +		mountlist +		MOUNTPROC_DUMP(void) = 2; + +		/* +		 * Removes the mount list entry for the directory +		 * Unix authentication required. +		 */ +		void +		MOUNTPROC_UMNT(dirpath) = 3; + +		/* +		 * Removes all of the mount list entries for this client +		 * Unix authentication required. +		 */ +		void +		MOUNTPROC_UMNTALL(void) = 4; + +		/* +		 * Returns a list of all the exported filesystems, and which +		 * machines are allowed to import it. +		 */ +		exports +		MOUNTPROC_EXPORT(void)  = 5; + +		/* +		 * Identical to MOUNTPROC_EXPORT above +		 */ +		exports +		MOUNTPROC_EXPORTALL(void) = 6; +	} = 1; +} = 100005; diff --git a/lib/librpc/rpcsvc/nfs_prot.x b/lib/librpc/rpcsvc/nfs_prot.x new file mode 100644 index 000000000000..7633e5add47d --- /dev/null +++ b/lib/librpc/rpcsvc/nfs_prot.x @@ -0,0 +1,355 @@ +/* @(#)nfs_prot.x	2.1 88/08/01 4.0 RPCSRC */ + +/* + * Sun RPC is a product of Sun Microsystems, Inc. and is provided for + * unrestricted use provided that this legend is included on all tape + * media and as a part of the software program in whole or part.  Users + * may copy or modify Sun RPC without charge, but are not authorized + * to license or distribute it to anyone else except as part of a product or + * program developed by the user. + *  + * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE + * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR + * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. + *  + * Sun RPC is provided with no support and without any obligation on the + * part of Sun Microsystems, Inc. to assist in its use, correction, + * modification or enhancement. + *  + * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE + * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC + * OR ANY PART THEREOF. + *  + * In no event will Sun Microsystems, Inc. be liable for any lost revenue + * or profits or other special, indirect and consequential damages, even if + * Sun has been advised of the possibility of such damages. + *  + * Sun Microsystems, Inc. + * 2550 Garcia Avenue + * Mountain View, California  94043 + */ + +/* + * nfs_prot.x 1.2 87/10/12 + * Copyright 1987 Sun Microsystems, Inc. + */ +const NFS_PORT          = 2049; +const NFS_MAXDATA       = 8192; +const NFS_MAXPATHLEN    = 1024; +const NFS_MAXNAMLEN	= 255; +const NFS_FHSIZE	= 32; +const NFS_COOKIESIZE	= 4; +const NFS_FIFO_DEV	= -1;	/* size kludge for named pipes */ + +/* + * File types + */ +const NFSMODE_FMT  = 0170000;	/* type of file */ +const NFSMODE_DIR  = 0040000;	/* directory */ +const NFSMODE_CHR  = 0020000;	/* character special */ +const NFSMODE_BLK  = 0060000;	/* block special */ +const NFSMODE_REG  = 0100000;	/* regular */ +const NFSMODE_LNK  = 0120000;	/* symbolic link */ +const NFSMODE_SOCK = 0140000;	/* socket */ +const NFSMODE_FIFO = 0010000;	/* fifo */ + +/* + * Error status + */ +enum nfsstat { +	NFS_OK= 0,		/* no error */ +	NFSERR_PERM=1,		/* Not owner */ +	NFSERR_NOENT=2,		/* No such file or directory */ +	NFSERR_IO=5,		/* I/O error */ +	NFSERR_NXIO=6,		/* No such device or address */ +	NFSERR_ACCES=13,	/* Permission denied */ +	NFSERR_EXIST=17,	/* File exists */ +	NFSERR_NODEV=19,	/* No such device */ +	NFSERR_NOTDIR=20,	/* Not a directory*/ +	NFSERR_ISDIR=21,	/* Is a directory */ +	NFSERR_FBIG=27,		/* File too large */ +	NFSERR_NOSPC=28,	/* No space left on device */ +	NFSERR_ROFS=30,		/* Read-only file system */ +	NFSERR_NAMETOOLONG=63,	/* File name too long */ +	NFSERR_NOTEMPTY=66,	/* Directory not empty */ +	NFSERR_DQUOT=69,	/* Disc quota exceeded */ +	NFSERR_STALE=70,	/* Stale NFS file handle */ +	NFSERR_WFLUSH=99	/* write cache flushed */ +}; + +/* + * File types + */ +enum ftype { +	NFNON = 0,	/* non-file */ +	NFREG = 1,	/* regular file */ +	NFDIR = 2,	/* directory */ +	NFBLK = 3,	/* block special */ +	NFCHR = 4,	/* character special */ +	NFLNK = 5,	/* symbolic link */ +	NFSOCK = 6,	/* unix domain sockets */ +	NFBAD = 7,	/* unused */ +	NFFIFO = 8 	/* named pipe */ +}; + +/* + * File access handle + */ +struct nfs_fh { +	opaque data[NFS_FHSIZE]; +}; + +/*  + * Timeval + */ +struct nfstime { +	unsigned seconds; +	unsigned useconds; +}; + + +/* + * File attributes + */ +struct fattr { +	ftype type;		/* file type */ +	unsigned mode;		/* protection mode bits */ +	unsigned nlink;		/* # hard links */ +	unsigned uid;		/* owner user id */ +	unsigned gid;		/* owner group id */ +	unsigned size;		/* file size in bytes */ +	unsigned blocksize;	/* prefered block size */ +	unsigned rdev;		/* special device # */ +	unsigned blocks;	/* Kb of disk used by file */ +	unsigned fsid;		/* device # */ +	unsigned fileid;	/* inode # */ +	nfstime	atime;		/* time of last access */ +	nfstime	mtime;		/* time of last modification */ +	nfstime	ctime;		/* time of last change */ +}; + +/* + * File attributes which can be set + */ +struct sattr { +	unsigned mode;	/* protection mode bits */ +	unsigned uid;	/* owner user id */ +	unsigned gid;	/* owner group id */ +	unsigned size;	/* file size in bytes */ +	nfstime	atime;	/* time of last access */ +	nfstime	mtime;	/* time of last modification */ +}; + + +typedef string filename<NFS_MAXNAMLEN>;  +typedef string nfspath<NFS_MAXPATHLEN>; + +/* + * Reply status with file attributes + */ +union attrstat switch (nfsstat status) { +case NFS_OK: +	fattr attributes; +default: +	void; +}; + +struct sattrargs { +	nfs_fh file; +	sattr attributes; +}; + +/* + * Arguments for directory operations + */ +struct diropargs { +	nfs_fh	dir;	/* directory file handle */ +	filename name;		/* name (up to NFS_MAXNAMLEN bytes) */ +}; + +struct diropokres { +	nfs_fh file; +	fattr attributes; +}; + +/* + * Results from directory operation + */ +union diropres switch (nfsstat status) { +case NFS_OK: +	diropokres diropres; +default: +	void; +}; + +union readlinkres switch (nfsstat status) { +case NFS_OK: +	nfspath data; +default: +	void; +}; + +/* + * Arguments to remote read + */ +struct readargs { +	nfs_fh file;		/* handle for file */ +	unsigned offset;	/* byte offset in file */ +	unsigned count;		/* immediate read count */ +	unsigned totalcount;	/* total read count (from this offset)*/ +}; + +/* + * Status OK portion of remote read reply + */ +struct readokres { +	fattr	attributes;	/* attributes, need for pagin*/ +	opaque data<NFS_MAXDATA>; +}; + +union readres switch (nfsstat status) { +case NFS_OK: +	readokres reply; +default: +	void; +}; + +/* + * Arguments to remote write  + */ +struct writeargs { +	nfs_fh	file;		/* handle for file */ +	unsigned beginoffset;	/* beginning byte offset in file */ +	unsigned offset;	/* current byte offset in file */ +	unsigned totalcount;	/* total write count (to this offset)*/ +	opaque data<NFS_MAXDATA>; +}; + +struct createargs { +	diropargs where; +	sattr attributes; +}; + +struct renameargs { +	diropargs from; +	diropargs to; +}; + +struct linkargs { +	nfs_fh from; +	diropargs to; +}; + +struct symlinkargs { +	diropargs from; +	nfspath to; +	sattr attributes; +}; + + +typedef opaque nfscookie[NFS_COOKIESIZE]; + +/* + * Arguments to readdir + */ +struct readdirargs { +	nfs_fh dir;		/* directory handle */ +	nfscookie cookie; +	unsigned count;		/* number of directory bytes to read */ +}; + +struct entry { +	unsigned fileid; +	filename name; +	nfscookie cookie; +	entry *nextentry; +}; + +struct dirlist { +	entry *entries; +	bool eof; +}; + +union readdirres switch (nfsstat status) { +case NFS_OK: +	dirlist reply; +default: +	void; +}; + +struct statfsokres { +	unsigned tsize;	/* preferred transfer size in bytes */ +	unsigned bsize;	/* fundamental file system block size */ +	unsigned blocks;	/* total blocks in file system */ +	unsigned bfree;	/* free blocks in fs */ +	unsigned bavail;	/* free blocks avail to non-superuser */ +}; + +union statfsres switch (nfsstat status) { +case NFS_OK: +	statfsokres reply; +default: +	void; +}; + +/* + * Remote file service routines + */ +program NFS_PROGRAM { +	version NFS_VERSION { +		void  +		NFSPROC_NULL(void) = 0; + +		attrstat  +		NFSPROC_GETATTR(nfs_fh) =	1; + +		attrstat  +		NFSPROC_SETATTR(sattrargs) = 2; + +		void  +		NFSPROC_ROOT(void) = 3; + +		diropres  +		NFSPROC_LOOKUP(diropargs) = 4; + +		readlinkres  +		NFSPROC_READLINK(nfs_fh) = 5; + +		readres  +		NFSPROC_READ(readargs) = 6; + +		void  +		NFSPROC_WRITECACHE(void) = 7; + +		attrstat +		NFSPROC_WRITE(writeargs) = 8; + +		diropres +		NFSPROC_CREATE(createargs) = 9; + +		nfsstat +		NFSPROC_REMOVE(diropargs) = 10; + +		nfsstat +		NFSPROC_RENAME(renameargs) = 11; + +		nfsstat +		NFSPROC_LINK(linkargs) = 12; + +		nfsstat +		NFSPROC_SYMLINK(symlinkargs) = 13; + +		diropres +		NFSPROC_MKDIR(createargs) = 14; + +		nfsstat +		NFSPROC_RMDIR(diropargs) = 15; + +		readdirres +		NFSPROC_READDIR(readdirargs) = 16; + +		statfsres +		NFSPROC_STATFS(nfs_fh) = 17; +	} = 2; +} = 100003; + diff --git a/lib/librpc/rpcsvc/nlm_prot.x b/lib/librpc/rpcsvc/nlm_prot.x new file mode 100644 index 000000000000..e60c9315c24a --- /dev/null +++ b/lib/librpc/rpcsvc/nlm_prot.x @@ -0,0 +1,179 @@ +/* @(#)nlm_prot.x	2.1 88/08/01 4.0 RPCSRC */ +/* @(#)nlm_prot.x 1.8 87/09/21 Copyr 1987 Sun Micro */ + +/* + * Network lock manager protocol definition + * Copyright (C) 1986 Sun Microsystems, Inc. + * + * protocol used between local lock manager and remote lock manager + */ + +#ifdef RPC_HDR +%#define LM_MAXSTRLEN	1024 +%#define MAXNAMELEN	LM_MAXSTRLEN+1 +#endif + +/* + * status of a call to the lock manager + */ +enum nlm_stats { +	nlm_granted = 0, +	nlm_denied = 1, +	nlm_denied_nolocks = 2, +	nlm_blocked = 3, +	nlm_denied_grace_period = 4 +}; + +struct nlm_holder { +	bool exclusive; +	int svid; +	netobj oh; +	unsigned l_offset; +	unsigned l_len; +}; + +union nlm_testrply switch (nlm_stats stat) { +	case nlm_denied: +		struct nlm_holder holder; +	default: +		void; +}; + +struct nlm_stat { +	nlm_stats stat; +}; + +struct nlm_res { +	netobj cookie; +	nlm_stat stat; +}; + +struct nlm_testres { +	netobj cookie; +	nlm_testrply stat; +}; + +struct nlm_lock { +	string caller_name<LM_MAXSTRLEN>; +	netobj fh;		/* identify a file */ +	netobj oh;		/* identify owner of a lock */ +	int svid;		/* generated from pid for svid */ +	unsigned l_offset; +	unsigned l_len; +}; + +struct nlm_lockargs { +	netobj cookie; +	bool block; +	bool exclusive; +	struct nlm_lock alock; +	bool reclaim;		/* used for recovering locks */ +	int state;		/* specify local status monitor state */ +}; + +struct nlm_cancargs { +	netobj cookie;		 +	bool block; +	bool exclusive; +	struct nlm_lock alock; +}; + +struct nlm_testargs { +	netobj cookie;		 +	bool exclusive; +	struct nlm_lock alock; +}; + +struct nlm_unlockargs { +	netobj cookie;		 +	struct nlm_lock alock; +}; + + +#ifdef RPC_HDR +%/* +% * The following enums are actually bit encoded for efficient +% * boolean algebra.... DON'T change them..... +% */ +#endif +enum	fsh_mode { +	fsm_DN  = 0,	/* deny none */ +	fsm_DR  = 1,	/* deny read */ +	fsm_DW  = 2,	/* deny write */ +	fsm_DRW = 3	/* deny read/write */ +}; + +enum	fsh_access { +	fsa_NONE = 0,	/* for completeness */ +	fsa_R    = 1,	/* read only */ +	fsa_W    = 2,	/* write only */ +	fsa_RW   = 3	/* read/write */ +}; + +struct	nlm_share { +	string caller_name<LM_MAXSTRLEN>; +	netobj	fh; +	netobj	oh; +	fsh_mode	mode; +	fsh_access	access; +}; + +struct	nlm_shareargs { +	netobj	cookie; +	nlm_share	share; +	bool	reclaim; +}; + +struct	nlm_shareres { +	netobj	cookie; +	nlm_stats	stat; +	int	sequence; +}; + +struct	nlm_notify { +	string name<MAXNAMELEN>; +	long state; +}; + +/* + * Over-the-wire protocol used between the network lock managers + */ + +program NLM_PROG { +	version NLM_VERS { + +		nlm_testres	NLM_TEST(struct nlm_testargs) =	1; + +		nlm_res		NLM_LOCK(struct nlm_lockargs) =	2; + +		nlm_res		NLM_CANCEL(struct nlm_cancargs) = 3; +		nlm_res		NLM_UNLOCK(struct nlm_unlockargs) =	4; + +		/* +		 * remote lock manager call-back to grant lock +		 */ +		nlm_res		NLM_GRANTED(struct nlm_testargs)= 5; +		/* +		 * message passing style of requesting lock +		 */ +		void		NLM_TEST_MSG(struct nlm_testargs) = 6; +		void		NLM_LOCK_MSG(struct nlm_lockargs) = 7; +		void		NLM_CANCEL_MSG(struct nlm_cancargs) =8; +		void		NLM_UNLOCK_MSG(struct nlm_unlockargs) = 9; +		void		NLM_GRANTED_MSG(struct nlm_testargs) = 10; +		void		NLM_TEST_RES(nlm_testres) = 11; +		void		NLM_LOCK_RES(nlm_res) = 12; +		void		NLM_CANCEL_RES(nlm_res) = 13; +		void		NLM_UNLOCK_RES(nlm_res) = 14; +		void		NLM_GRANTED_RES(nlm_res) = 15; +	} = 1; + +	version NLM_VERSX { +		nlm_shareres	NLM_SHARE(nlm_shareargs) = 20; +		nlm_shareres	NLM_UNSHARE(nlm_shareargs) = 21; +		nlm_res		NLM_NM_LOCK(nlm_lockargs) = 22; +		void		NLM_FREE_ALL(nlm_notify) = 23; +	} = 3; + +} = 100021; + diff --git a/lib/librpc/rpcsvc/rex.x b/lib/librpc/rpcsvc/rex.x new file mode 100644 index 000000000000..6063fdd28a57 --- /dev/null +++ b/lib/librpc/rpcsvc/rex.x @@ -0,0 +1,229 @@ +/* @(#)rex.x	2.1 88/08/01 4.0 RPCSRC */ +/* @(#)rex.x 1.3 87/09/18 Copyr 1987 Sun Micro */ + +/* + * Sun RPC is a product of Sun Microsystems, Inc. and is provided for + * unrestricted use provided that this legend is included on all tape + * media and as a part of the software program in whole or part.  Users + * may copy or modify Sun RPC without charge, but are not authorized + * to license or distribute it to anyone else except as part of a product or + * program developed by the user. + *  + * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE + * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR + * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. + *  + * Sun RPC is provided with no support and without any obligation on the + * part of Sun Microsystems, Inc. to assist in its use, correction, + * modification or enhancement. + *  + * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE + * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC + * OR ANY PART THEREOF. + *  + * In no event will Sun Microsystems, Inc. be liable for any lost revenue + * or profits or other special, indirect and consequential damages, even if + * Sun has been advised of the possibility of such damages. + *  + * Sun Microsystems, Inc. + * 2550 Garcia Avenue + * Mountain View, California  94043 + */ + +/* + * Remote execution (rex) protocol specification + */ + +const STRINGSIZE = 1024; +typedef string rexstring<1024>; + +/* + * values to pass to REXPROC_SIGNAL + */ +const SIGINT = 2;	/* interrupt */ + +/* + * Values for rst_flags, below  + */ +const REX_INTERACTIVE = 1;	/* interactive mode */ + +struct rex_start { +	rexstring rst_cmd<>;	/* list of command and args */ +	rexstring rst_host;	/* working directory host name */ +	rexstring rst_fsname;	/* working directory file system name */ +	rexstring rst_dirwithin;/* working directory within file system */ +	rexstring rst_env<>;	/* list of environment */ +	unsigned int rst_port0;	/* port for stdin */ +	unsigned int rst_port1;	/* port for stdout */ +	unsigned int rst_port2;	/* port for stderr */ +	unsigned int rst_flags;	/* options - see const above */ +}; + +struct rex_result { +   	int rlt_stat;		/* integer status code */ +	rexstring rlt_message;	/* string message for human consumption */ +}; + + +struct sgttyb { +	unsigned four;	/* always equals 4 */ +	opaque chars[4]; +	/* chars[0] == input speed */ +	/* chars[1] == output speed */ +	/* chars[2] == kill character */ +	/* chars[3] == erase character */ +	unsigned flags; +}; +/* values for speeds above (baud rates)  */ +const B0  = 0; +const B50 = 1; +const B75 = 2; +const B110 = 3; +const B134 = 4; +const B150 = 5; +const B200 = 6; +const B300 = 7; +const B600 = 8; +const B1200 = 9; +const B1800 = 10; +const B2400 = 11; +const B4800 = 12; +const B9600 = 13; +const B19200 = 14; +const B38400 = 15; + +/* values for flags above */ +const TANDEM = 0x00000001; /* send stopc on out q full */ +const CBREAK = 0x00000002; /* half-cooked mode */ +const LCASE = 0x00000004; /* simulate lower case */ +const ECHO = 0x00000008; /* echo input */ +const CRMOD = 0x00000010; /* map \r to \r\n on output */ +const RAW = 0x00000020; /* no i/o processing */ +const ODDP = 0x00000040; /* get/send odd parity */ +const EVENP = 0x00000080; /* get/send even parity */ +const ANYP = 0x000000c0; /* get any parity/send none */ +const NLDELAY = 0x00000300; /* \n delay */ +const  NL0 = 0x00000000; +const  NL1 = 0x00000100; /* tty 37 */ +const  NL2 = 0x00000200; /* vt05 */ +const  NL3 = 0x00000300; +const TBDELAY = 0x00000c00; /* horizontal tab delay */ +const  TAB0 = 0x00000000; +const  TAB1 = 0x00000400; /* tty 37 */ +const  TAB2 = 0x00000800; +const XTABS = 0x00000c00; /* expand tabs on output */ +const CRDELAY = 0x00003000; /* \r delay */ +const  CR0 = 0x00000000; +const  CR1 = 0x00001000; /* tn 300 */ +const  CR2 = 0x00002000; /* tty 37 */ +const  CR3 = 0x00003000; /* concept 100 */ +const VTDELAY = 0x00004000; /* vertical tab delay */ +const  FF0 = 0x00000000; +const  FF1 = 0x00004000; /* tty 37 */ +const BSDELAY = 0x00008000; /* \b delay */ +const  BS0 = 0x00000000; +const  BS1 = 0x00008000; +const CRTBS = 0x00010000; /* do backspacing for crt */ +const PRTERA = 0x00020000; /* \ ... / erase */ +const CRTERA = 0x00040000; /* " \b " to wipe out char */ +const TILDE = 0x00080000; /* hazeltine tilde kludge */ +const MDMBUF = 0x00100000; /* start/stop output on carrier intr */ +const LITOUT = 0x00200000; /* literal output */ +const TOSTOP = 0x00400000; /* SIGTTOU on background output */ +const FLUSHO = 0x00800000; /* flush output to terminal */ +const NOHANG = 0x01000000; /* no SIGHUP on carrier drop */ +const L001000 = 0x02000000; +const CRTKIL = 0x04000000; /* kill line with " \b " */ +const PASS8 = 0x08000000; +const CTLECH = 0x10000000; /* echo control chars as ^X */ +const PENDIN = 0x20000000; /* tp->t_rawq needs reread */ +const DECCTQ = 0x40000000; /* only ^Q starts after ^S */ +const NOFLSH = 0x80000000; /* no output flush on signal */ + +struct tchars { +	unsigned six;	/* always equals 6 */ +	opaque chars[6]; +	/* chars[0] == interrupt char */ +	/* chars[1] == quit char */ +	/* chars[2] == start output char */ +	/* chars[3] == stop output char */ +	/* chars[4] == end-of-file char */ +	/* chars[5] == input delimeter (like nl) */ +}; + +struct ltchars { +	unsigned six;	/* always equals 6 */ +	opaque chars[6]; +	/* chars[0] == stop process signal */ +	/* chars[1] == delayed stop process signal */ +	/* chars[2] == reprint line */ +	/* chars[3] == flush output */ +	/* chars[4] == word erase */ +	/* chars[5] == literal next character */ +	unsigned mode; +}; + +struct rex_ttysize { +	int ts_lines; +	int ts_cols; +}; + +struct rex_ttymode { +    sgttyb basic;    /* standard unix tty flags */ +    tchars more; /* interrupt, kill characters, etc. */ +    ltchars yetmore; /* special Berkeley characters */ +    unsigned andmore;     /* and Berkeley modes */ +}; + +/* values for andmore above */ +const LCRTBS = 0x0001;	/* do backspacing for crt */ +const LPRTERA = 0x0002;	/* \ ... / erase */ +const LCRTERA = 0x0004;	/* " \b " to wipe out char */ +const LTILDE = 0x0008;	/* hazeltine tilde kludge */ +const LMDMBUF = 0x0010;	/* start/stop output on carrier intr */ +const LLITOUT = 0x0020;	/* literal output */ +const LTOSTOP = 0x0040;	/* SIGTTOU on background output */ +const LFLUSHO = 0x0080;	/* flush output to terminal */ +const LNOHANG = 0x0100;	/* no SIGHUP on carrier drop */ +const LL001000 = 0x0200; +const LCRTKIL = 0x0400;	/* kill line with " \b " */ +const LPASS8 = 0x0800; +const LCTLECH = 0x1000;	/* echo control chars as ^X */ +const LPENDIN = 0x2000;	/* needs reread */ +const LDECCTQ = 0x4000;	/* only ^Q starts after ^S */ +const LNOFLSH = 0x8000;	/* no output flush on signal */ + +program REXPROG { +	version REXVERS { + +		/* +		 * Start remote execution +		 */ +		rex_result  +		REXPROC_START(rex_start) = 1; + +		/* +		 * Wait for remote execution to terminate +		 */ +		rex_result +		REXPROC_WAIT(void) = 2; + +		/* +		 * Send tty modes +		 */ +		void +		REXPROC_MODES(rex_ttymode) = 3; + +		/* +		 * Send window size change +		 */ +		void +		REXPROC_WINCH(rex_ttysize) = 4; + +		/* +		 * Send other signal +		 */ +		void +		REXPROC_SIGNAL(int) = 5; +	} = 1; +} = 100017; diff --git a/lib/librpc/rpcsvc/rnusers.x b/lib/librpc/rpcsvc/rnusers.x new file mode 100644 index 000000000000..257df1e6e91d --- /dev/null +++ b/lib/librpc/rpcsvc/rnusers.x @@ -0,0 +1,86 @@ +/* @(#)rnusers.x	2.1 88/08/01 4.0 RPCSRC */ +/* @(#)rnusers.x 1.2 87/09/20 Copyr 1987 Sun Micro */ + +/* + * Sun RPC is a product of Sun Microsystems, Inc. and is provided for + * unrestricted use provided that this legend is included on all tape + * media and as a part of the software program in whole or part.  Users + * may copy or modify Sun RPC without charge, but are not authorized + * to license or distribute it to anyone else except as part of a product or + * program developed by the user. + *  + * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE + * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR + * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. + *  + * Sun RPC is provided with no support and without any obligation on the + * part of Sun Microsystems, Inc. to assist in its use, correction, + * modification or enhancement. + *  + * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE + * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC + * OR ANY PART THEREOF. + *  + * In no event will Sun Microsystems, Inc. be liable for any lost revenue + * or profits or other special, indirect and consequential damages, even if + * Sun has been advised of the possibility of such damages. + *  + * Sun Microsystems, Inc. + * 2550 Garcia Avenue + * Mountain View, California  94043 + */ + +/* + * Find out about remote users + */ + +const MAXUSERS = 100; +const MAXUTLEN = 256; + +struct utmp { +	string ut_line<MAXUTLEN>; +	string ut_name<MAXUTLEN>; +	string ut_host<MAXUTLEN>; +	int ut_time; +}; + + +struct utmpidle { +	utmp ui_utmp; +	unsigned int ui_idle; +}; + +typedef utmp utmparr<MAXUSERS>; + +typedef utmpidle utmpidlearr<MAXUSERS>; + +program RUSERSPROG { +	/* +	 * Includes idle information +	 */ +	version RUSERSVERS_IDLE { +		int +		RUSERSPROC_NUM(void) = 1; + +		utmpidlearr +		RUSERSPROC_NAMES(void) = 2; + +		utmpidlearr +		RUSERSPROC_ALLNAMES(void) = 3; +	} = 1; + +	/* +	 * Old version does not include idle information +	 */ +	version RUSERSVERS_ORIG { +		int +		RUSERSPROC_NUM(void) = 1; + +		utmparr +		RUSERSPROC_NAMES(void) = 2; + +		utmparr +		RUSERSPROC_ALLNAMES(void) = 3; +	} = 2; +} = 100002; +	 diff --git a/lib/librpc/rpcsvc/rquota.x b/lib/librpc/rpcsvc/rquota.x new file mode 100644 index 000000000000..62888f612a78 --- /dev/null +++ b/lib/librpc/rpcsvc/rquota.x @@ -0,0 +1,61 @@ +/* @(#)rquota.x	2.1 88/08/01 4.0 RPCSRC */ +/* @(#)rquota.x 1.2 87/09/20 Copyr 1987 Sun Micro */ + +/* + * Remote quota protocol + * Requires unix authentication + */ + +const RQ_PATHLEN = 1024; + +struct getquota_args { +	string gqa_pathp<RQ_PATHLEN>;  	/* path to filesystem of interest */ +	int gqa_uid;	        	/* inquire about quota for uid */ +}; + +/* + * remote quota structure + */ +struct rquota { +	int rq_bsize;			/* block size for block counts */ +	bool rq_active;  		/* indicates whether quota is active */ +	unsigned int rq_bhardlimit;	/* absolute limit on disk blks alloc */ +	unsigned int rq_bsoftlimit;	/* preferred limit on disk blks */ +	unsigned int rq_curblocks;	/* current block count */ +	unsigned int rq_fhardlimit;	/* absolute limit on allocated files */ +	unsigned int rq_fsoftlimit;	/* preferred file limit */ +	unsigned int rq_curfiles;	/* current # allocated files */ +	unsigned int rq_btimeleft;	/* time left for excessive disk use */ +	unsigned int rq_ftimeleft;	/* time left for excessive files */ +};	 + +enum gqr_status { +	Q_OK = 1,		/* quota returned */ +	Q_NOQUOTA = 2,  	/* noquota for uid */ +	Q_EPERM = 3		/* no permission to access quota */ +}; + +union getquota_rslt switch (gqr_status status) { +case Q_OK: +	rquota gqr_rquota;	/* valid if status == Q_OK */ +case Q_NOQUOTA: +	void; +case Q_EPERM: +	void; +}; + +program RQUOTAPROG { +	version RQUOTAVERS { +		/* +		 * Get all quotas +		 */ +		getquota_rslt +		RQUOTAPROC_GETQUOTA(getquota_args) = 1; + +		/* +	 	 * Get active quotas only +		 */ +		getquota_rslt +		RQUOTAPROC_GETACTIVEQUOTA(getquota_args) = 2; +	} = 1; +} = 100011; diff --git a/lib/librpc/rpcsvc/rstat.c b/lib/librpc/rpcsvc/rstat.c new file mode 100644 index 000000000000..fe83ae51a0ac --- /dev/null +++ b/lib/librpc/rpcsvc/rstat.c @@ -0,0 +1,85 @@ +/* @(#)rstat.c	2.3 88/11/30 4.0 RPCSRC */ +/* + *  Simple program that prints the status of a remote host, in a format + *  similar to that used by the 'w' command, using the rstat.x service. + */ + +#include <stdio.h> +#include <sys/param.h> +#include <rpc/rpc.h>        /* include <sys/time.h> */ +#include "rstat.h" + +main(argc, argv) +int argc; +char **argv; +{ + +    char        *host; +    CLIENT      *rstat_clnt; +    statstime   *host_stat; +    struct tm   *tmp_time; +    struct tm    host_time; +    struct tm    host_uptime; +    char         days_buf[16]; +    char         hours_buf[16]; + +    if (argc != 2) +    { +        fprintf(stderr, "usage: %s \"host\"\n", argv[0]); +        exit(1); +    } + +    host = argv[1]; + +    /* client handle to rstat */ +    rstat_clnt = clnt_create(host, RSTATPROG, RSTATVERS_TIME, "udp"); +    if (rstat_clnt == NULL) +    { +        clnt_pcreateerror(argv[0]); +        exit(1); +    } + +    host_stat = rstatproc_stats_3(NULL, rstat_clnt); +    if (host_stat == NULL) +    { +        clnt_perror(rstat_clnt, argv[0]); +        exit(1); +    } + +    tmp_time = localtime(&host_stat->curtime.tv_sec); +    host_time = *tmp_time; + +    host_stat->curtime.tv_sec -= host_stat->boottime.tv_sec; + +    tmp_time = gmtime(&host_stat->curtime.tv_sec); +    host_uptime = *tmp_time; + +    if (host_uptime.tm_yday != 0) +        sprintf(days_buf, "%d day%s, ", host_uptime.tm_yday, +            (host_uptime.tm_yday > 1) ? "s" : ""); +    else +        days_buf[0] = '\0'; + +    if (host_uptime.tm_hour != 0) +        sprintf(hours_buf, "%2d:%02d,", +            host_uptime.tm_hour, host_uptime.tm_min); +    else +    if (host_uptime.tm_min != 0) +        sprintf(hours_buf, "%2d mins,", host_uptime.tm_min); +    else +        hours_buf[0] = '\0'; + +    printf(" %2d:%02d%cm  up %s%s load average: %.2f %.2f %.2f\n", +        (host_time.tm_hour > 12)  ? host_time.tm_hour - 12 +                                  : host_time.tm_hour, +        host_time.tm_min, +        (host_time.tm_hour >= 12) ? 'p' +                                  : 'a', +        days_buf, +        hours_buf, +        (double)host_stat->avenrun[0]/FSCALE, +        (double)host_stat->avenrun[1]/FSCALE, +        (double)host_stat->avenrun[2]/FSCALE); + +    exit(0); +} diff --git a/lib/librpc/rpcsvc/rstat.x b/lib/librpc/rpcsvc/rstat.x new file mode 100644 index 000000000000..6367c4394321 --- /dev/null +++ b/lib/librpc/rpcsvc/rstat.x @@ -0,0 +1,145 @@ +/* @(#)rstat.x	2.2 88/08/01 4.0 RPCSRC */ +/* @(#)rstat.x 1.2 87/09/18 Copyr 1987 Sun Micro */ + +/* + * Sun RPC is a product of Sun Microsystems, Inc. and is provided for + * unrestricted use provided that this legend is included on all tape + * media and as a part of the software program in whole or part.  Users + * may copy or modify Sun RPC without charge, but are not authorized + * to license or distribute it to anyone else except as part of a product or + * program developed by the user. + *  + * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE + * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR + * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. + *  + * Sun RPC is provided with no support and without any obligation on the + * part of Sun Microsystems, Inc. to assist in its use, correction, + * modification or enhancement. + *  + * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE + * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC + * OR ANY PART THEREOF. + *  + * In no event will Sun Microsystems, Inc. be liable for any lost revenue + * or profits or other special, indirect and consequential damages, even if + * Sun has been advised of the possibility of such damages. + *  + * Sun Microsystems, Inc. + * 2550 Garcia Avenue + * Mountain View, California  94043 + */ + +/* + * Gather statistics on remote machines + */ + +#ifdef RPC_HDR + +%#ifndef FSCALE +%/* +% * Scale factor for scaled integers used to count load averages. +% */ +%#define FSHIFT  8               /* bits to right of fixed binary point */ +%#define FSCALE  (1<<FSHIFT) +% +%#endif /* ndef FSCALE */ + +#endif /* def RPC_HDR */ + +const CPUSTATES = 4; +const DK_NDRIVE = 4; + +/* + * GMT since 0:00, January 1, 1970 + */ +struct rstat_timeval { +	unsigned int tv_sec;	/* seconds */ +	unsigned int tv_usec;	/* and microseconds */ +}; + +struct statstime {				/* RSTATVERS_TIME */ +	int cp_time[CPUSTATES]; +	int dk_xfer[DK_NDRIVE]; +	unsigned int v_pgpgin;	/* these are cumulative sum */ +	unsigned int v_pgpgout; +	unsigned int v_pswpin; +	unsigned int v_pswpout; +	unsigned int v_intr; +	int if_ipackets; +	int if_ierrors; +	int if_oerrors; +	int if_collisions; +	unsigned int v_swtch; +	int avenrun[3];         /* scaled by FSCALE */ +	rstat_timeval boottime; +	rstat_timeval curtime; +	int if_opackets; +}; + +struct statsswtch {			/* RSTATVERS_SWTCH */ +	int cp_time[CPUSTATES]; +	int dk_xfer[DK_NDRIVE]; +	unsigned int v_pgpgin;	/* these are cumulative sum */ +	unsigned int v_pgpgout; +	unsigned int v_pswpin; +	unsigned int v_pswpout; +	unsigned int v_intr; +	int if_ipackets; +	int if_ierrors; +	int if_oerrors; +	int if_collisions; +	unsigned int v_swtch; +	unsigned int avenrun[3];/* scaled by FSCALE */ +	rstat_timeval boottime; +	int if_opackets; +}; + +struct stats {				/* RSTATVERS_ORIG */ +	int cp_time[CPUSTATES]; +	int dk_xfer[DK_NDRIVE]; +	unsigned int v_pgpgin;	/* these are cumulative sum */ +	unsigned int v_pgpgout; +	unsigned int v_pswpin; +	unsigned int v_pswpout; +	unsigned int v_intr; +	int if_ipackets; +	int if_ierrors; +	int if_oerrors; +	int if_collisions; +	int if_opackets; +}; + + +program RSTATPROG { +	/* +	 * Newest version includes current time and context switching info +	 */ +	version RSTATVERS_TIME { +		statstime +		RSTATPROC_STATS(void) = 1; + +		unsigned int +		RSTATPROC_HAVEDISK(void) = 2; +	} = 3; +	/* +	 * Does not have current time +	 */ +	version RSTATVERS_SWTCH { +		statsswtch +		RSTATPROC_STATS(void) = 1; + +		unsigned int +		RSTATPROC_HAVEDISK(void) = 2; +	} = 2; +	/* +	 * Old version has no info about current time or context switching +	 */ +	version RSTATVERS_ORIG { +		stats +		RSTATPROC_STATS(void) = 1; + +		unsigned int +		RSTATPROC_HAVEDISK(void) = 2; +	} = 1; +} = 100001; diff --git a/lib/librpc/rpcsvc/rstat_proc.c b/lib/librpc/rpcsvc/rstat_proc.c new file mode 100644 index 000000000000..635120c6af64 --- /dev/null +++ b/lib/librpc/rpcsvc/rstat_proc.c @@ -0,0 +1,352 @@ +/* @(#)rstat_proc.c	2.2 88/08/01 4.0 RPCSRC */ +#ifndef lint +static  char sccsid[] = "@(#)rpc.rstatd.c 1.1 86/09/25 Copyr 1984 Sun Micro"; +#endif + +/* + * Copyright (c) 1984 by Sun Microsystems, Inc. + */ + +/* + * Sun RPC is a product of Sun Microsystems, Inc. and is provided for + * unrestricted use provided that this legend is included on all tape + * media and as a part of the software program in whole or part.  Users + * may copy or modify Sun RPC without charge, but are not authorized + * to license or distribute it to anyone else except as part of a product or + * program developed by the user. + * + * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE + * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR + * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. + * + * Sun RPC is provided with no support and without any obligation on the + * part of Sun Microsystems, Inc. to assist in its use, correction, + * modification or enhancement. + * + * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE + * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC + * OR ANY PART THEREOF. + * + * In no event will Sun Microsystems, Inc. be liable for any lost revenue + * or profits or other special, indirect and consequential damages, even if + * Sun has been advised of the possibility of such damages. + * + * Sun Microsystems, Inc. + * 2550 Garcia Avenue + * Mountain View, California  94043 + */ + +/* + * rstat service:  built with rstat.x and derived from rpc.rstatd.c + */ + +#include <signal.h> +#include <stdio.h> +#include <rpc/rpc.h> +#include <sys/socket.h> +#include <nlist.h> +#include <sys/dk.h> +#include <sys/errno.h> +#include <sys/vmmeter.h> +#include <net/if.h> +#include "rstat.h" + +struct nlist nl[] = { +#define	X_CPTIME	0 +	{ "_cp_time" }, +#define	X_SUM		1 +	{ "_sum" }, +#define	X_IFNET		2 +	{ "_ifnet" }, +#define	X_DKXFER	3 +	{ "_dk_xfer" }, +#define	X_BOOTTIME	4 +	{ "_boottime" }, +#define	X_AVENRUN	5 +	{ "_avenrun" }, +#define X_HZ		6 +	{ "_hz" }, +	"", +}; +int kmem; +int firstifnet, numintfs;	/* chain of ethernet interfaces */ +int stats_service(); + +/* + *  Define EXIT_WHEN_IDLE if you are able to have this program invoked + *  automatically on demand (as from inetd).  When defined, the service + *  will terminated after being idle for 20 seconds. + */ +int sincelastreq = 0;		/* number of alarms since last request */ +#ifdef EXIT_WHEN_IDLE +#define CLOSEDOWN 20		/* how long to wait before exiting */ +#endif /* def EXIT_WHEN_IDLE */ + +union { +    struct stats s1; +    struct statsswtch s2; +    struct statstime s3; +} stats_all; + +int updatestat(); +static stat_is_init = 0; +extern int errno; + +#ifndef FSCALE +#define FSCALE (1 << 8) +#endif + +stat_init() +{ +    stat_is_init = 1; +	setup(); +	updatestat(); +	alarm(1); +	signal(SIGALRM, updatestat); +    sleep(1);               /* allow for one wake-up */ +} + +statstime * +rstatproc_stats_3() +{ +    if (! stat_is_init) +        stat_init(); +    sincelastreq = 0; +    return(&stats_all.s3); +} + +statsswtch * +rstatproc_stats_2() +{ +    if (! stat_is_init) +        stat_init(); +    sincelastreq = 0; +    return(&stats_all.s2); +} + +stats * +rstatproc_stats_1() +{ +    if (! stat_is_init) +        stat_init(); +    sincelastreq = 0; +    return(&stats_all.s1); +} + +u_int * +rstatproc_havedisk_3() +{ +    static u_int have; + +    if (! stat_is_init) +        stat_init(); +    sincelastreq = 0; +    have = havedisk(); +	return(&have); +} + +u_int * +rstatproc_havedisk_2() +{ +    return(rstatproc_havedisk_3()); +} + +u_int * +rstatproc_havedisk_1() +{ +    return(rstatproc_havedisk_3()); +} + +updatestat() +{ +	int off, i, hz; +	struct vmmeter sum; +	struct ifnet ifnet; +	double avrun[3]; +	struct timeval tm, btm; + +#ifdef DEBUG +	fprintf(stderr, "entering updatestat\n"); +#endif +#ifdef EXIT_WHEN_IDLE +	if (sincelastreq >= CLOSEDOWN) { +#ifdef DEBUG +	fprintf(stderr, "about to closedown\n"); +#endif +		exit(0); +	} +	sincelastreq++; +#endif /* def EXIT_WHEN_IDLE */ +	if (lseek(kmem, (long)nl[X_HZ].n_value, 0) == -1) { +		fprintf(stderr, "rstat: can't seek in kmem\n"); +		exit(1); +	} +	if (read(kmem, (char *)&hz, sizeof hz) != sizeof hz) { +		fprintf(stderr, "rstat: can't read hz from kmem\n"); +		exit(1); +	} +	if (lseek(kmem, (long)nl[X_CPTIME].n_value, 0) == -1) { +		fprintf(stderr, "rstat: can't seek in kmem\n"); +		exit(1); +	} + 	if (read(kmem, (char *)stats_all.s1.cp_time, sizeof (stats_all.s1.cp_time)) +	    != sizeof (stats_all.s1.cp_time)) { +		fprintf(stderr, "rstat: can't read cp_time from kmem\n"); +		exit(1); +	} +	if (lseek(kmem, (long)nl[X_AVENRUN].n_value, 0) ==-1) { +		fprintf(stderr, "rstat: can't seek in kmem\n"); +		exit(1); +	} +#ifdef vax + 	if (read(kmem, (char *)avrun, sizeof (avrun)) != sizeof (avrun)) { +		fprintf(stderr, "rstat: can't read avenrun from kmem\n"); +		exit(1); +	} +	stats_all.s2.avenrun[0] = avrun[0] * FSCALE; +	stats_all.s2.avenrun[1] = avrun[1] * FSCALE; +	stats_all.s2.avenrun[2] = avrun[2] * FSCALE; +#endif +	if (lseek(kmem, (long)nl[X_BOOTTIME].n_value, 0) == -1) { +		fprintf(stderr, "rstat: can't seek in kmem\n"); +		exit(1); +	} + 	if (read(kmem, (char *)&btm, sizeof (stats_all.s2.boottime)) +	    != sizeof (stats_all.s2.boottime)) { +		fprintf(stderr, "rstat: can't read boottime from kmem\n"); +		exit(1); +	} +	stats_all.s2.boottime.tv_sec = btm.tv_sec; +	stats_all.s2.boottime.tv_usec = btm.tv_usec; + + +#ifdef DEBUG +	fprintf(stderr, "%d %d %d %d\n", stats_all.s1.cp_time[0], +	    stats_all.s1.cp_time[1], stats_all.s1.cp_time[2], stats_all.s1.cp_time[3]); +#endif + +	if (lseek(kmem, (long)nl[X_SUM].n_value, 0) ==-1) { +		fprintf(stderr, "rstat: can't seek in kmem\n"); +		exit(1); +	} + 	if (read(kmem, (char *)&sum, sizeof sum) != sizeof sum) { +		fprintf(stderr, "rstat: can't read sum from kmem\n"); +		exit(1); +	} +	stats_all.s1.v_pgpgin = sum.v_pgpgin; +	stats_all.s1.v_pgpgout = sum.v_pgpgout; +	stats_all.s1.v_pswpin = sum.v_pswpin; +	stats_all.s1.v_pswpout = sum.v_pswpout; +	stats_all.s1.v_intr = sum.v_intr; +	gettimeofday(&tm, (struct timezone *) 0); +	stats_all.s1.v_intr -= hz*(tm.tv_sec - btm.tv_sec) + +	    hz*(tm.tv_usec - btm.tv_usec)/1000000; +	stats_all.s2.v_swtch = sum.v_swtch; + +	if (lseek(kmem, (long)nl[X_DKXFER].n_value, 0) == -1) { +		fprintf(stderr, "rstat: can't seek in kmem\n"); +		exit(1); +	} + 	if (read(kmem, (char *)stats_all.s1.dk_xfer, sizeof (stats_all.s1.dk_xfer)) +	    != sizeof (stats_all.s1.dk_xfer)) { +		fprintf(stderr, "rstat: can't read dk_xfer from kmem\n"); +		exit(1); +	} + +	stats_all.s1.if_ipackets = 0; +	stats_all.s1.if_opackets = 0; +	stats_all.s1.if_ierrors = 0; +	stats_all.s1.if_oerrors = 0; +	stats_all.s1.if_collisions = 0; +	for (off = firstifnet, i = 0; off && i < numintfs; i++) { +		if (lseek(kmem, (long)off, 0) == -1) { +			fprintf(stderr, "rstat: can't seek in kmem\n"); +			exit(1); +		} +		if (read(kmem, (char *)&ifnet, sizeof ifnet) != sizeof ifnet) { +			fprintf(stderr, "rstat: can't read ifnet from kmem\n"); +			exit(1); +		} +		stats_all.s1.if_ipackets += ifnet.if_ipackets; +		stats_all.s1.if_opackets += ifnet.if_opackets; +		stats_all.s1.if_ierrors += ifnet.if_ierrors; +		stats_all.s1.if_oerrors += ifnet.if_oerrors; +		stats_all.s1.if_collisions += ifnet.if_collisions; +		off = (int) ifnet.if_next; +	} +	gettimeofday((struct timeval *)&stats_all.s3.curtime, +		(struct timezone *) 0); +	alarm(1); +} + +static  +setup() +{ +	struct ifnet ifnet; +	int off; + +	nlist("/vmunix", nl); +	if (nl[0].n_value == 0) { +		fprintf(stderr, "rstat: Variables missing from namelist\n"); +		exit (1); +	} +	if ((kmem = open("/dev/kmem", 0)) < 0) { +		fprintf(stderr, "rstat: can't open kmem\n"); +		exit(1); +	} + +	off = nl[X_IFNET].n_value; +	if (lseek(kmem, (long)off, 0) == -1) { +		fprintf(stderr, "rstat: can't seek in kmem\n"); +		exit(1); +	} +	if (read(kmem, (char *)&firstifnet, sizeof(int)) != sizeof (int)) { +		fprintf(stderr, "rstat: can't read firstifnet from kmem\n"); +		exit(1); +	} +	numintfs = 0; +	for (off = firstifnet; off;) { +		if (lseek(kmem, (long)off, 0) == -1) { +			fprintf(stderr, "rstat: can't seek in kmem\n"); +			exit(1); +		} +		if (read(kmem, (char *)&ifnet, sizeof ifnet) != sizeof ifnet) { +			fprintf(stderr, "rstat: can't read ifnet from kmem\n"); +			exit(1); +		} +		numintfs++; +		off = (int) ifnet.if_next; +	} +} + +/* + * returns true if have a disk + */ +static +havedisk() +{ +	int i, cnt; +	long  xfer[DK_NDRIVE]; + +	nlist("/vmunix", nl); +	if (nl[X_DKXFER].n_value == 0) { +		fprintf(stderr, "rstat: Variables missing from namelist\n"); +		exit (1); +	} +	if ((kmem = open("/dev/kmem", 0)) < 0) { +		fprintf(stderr, "rstat: can't open kmem\n"); +		exit(1); +	} +	if (lseek(kmem, (long)nl[X_DKXFER].n_value, 0) == -1) { +		fprintf(stderr, "rstat: can't seek in kmem\n"); +		exit(1); +	} +	if (read(kmem, (char *)xfer, sizeof xfer)!= sizeof xfer) { +		fprintf(stderr, "rstat: can't read kmem\n"); +		exit(1); +	} +	cnt = 0; +	for (i=0; i < DK_NDRIVE; i++) +		cnt += xfer[i]; +	return (cnt != 0); +} diff --git a/lib/librpc/rpcsvc/sm_inter.x b/lib/librpc/rpcsvc/sm_inter.x new file mode 100644 index 000000000000..2817ebfda3b4 --- /dev/null +++ b/lib/librpc/rpcsvc/sm_inter.x @@ -0,0 +1,116 @@ +/* @(#)sm_inter.x	2.2 88/08/01 4.0 RPCSRC */ +/* @(#)sm_inter.x 1.7 87/06/24 Copyr 1987 Sun Micro */ + +/* + * Sun RPC is a product of Sun Microsystems, Inc. and is provided for + * unrestricted use provided that this legend is included on all tape + * media and as a part of the software program in whole or part.  Users + * may copy or modify Sun RPC without charge, but are not authorized + * to license or distribute it to anyone else except as part of a product or + * program developed by the user. + *  + * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE + * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR + * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. + *  + * Sun RPC is provided with no support and without any obligation on the + * part of Sun Microsystems, Inc. to assist in its use, correction, + * modification or enhancement. + *  + * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE + * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC + * OR ANY PART THEREOF. + *  + * In no event will Sun Microsystems, Inc. be liable for any lost revenue + * or profits or other special, indirect and consequential damages, even if + * Sun has been advised of the possibility of such damages. + *  + * Sun Microsystems, Inc. + * 2550 Garcia Avenue + * Mountain View, California  94043 + */ + +/* + * Status monitor protocol specification + * Copyright (C) 1986 Sun Microsystems, Inc. + * + */ + + +program SM_PROG {  +	version SM_VERS  { +		/* res_stat = stat_succ if status monitor agrees to monitor */ +		/* res_stat = stat_fail if status monitor cannot monitor */ +		/* if res_stat == stat_succ, state = state number of site sm_name */ +		struct sm_stat_res			 SM_STAT(struct sm_name) = 1; + +		/* res_stat = stat_succ if status monitor agrees to monitor */ +		/* res_stat = stat_fail if status monitor cannot monitor */ +		/* stat consists of state number of local site */ +		struct sm_stat_res			 SM_MON(struct mon) = 2; + +		/* stat consists of state number of local site */ +		struct sm_stat				 SM_UNMON(struct mon_id) = 3; + +		/* stat consists of state number of local site */ +		struct sm_stat				 SM_UNMON_ALL(struct my_id) = 4; + +		void					 SM_SIMU_CRASH(void) = 5; + +	} = 1; +} = 100024; + +const	SM_MAXSTRLEN = 1024; + +struct sm_name { +	string mon_name<SM_MAXSTRLEN>; +}; + +struct my_id { +	string	 my_name<SM_MAXSTRLEN>;		/* name of the site iniates the monitoring request*/ +	int	my_prog;			/* rpc program # of the requesting process */ +	int	my_vers;			/* rpc version # of the requesting process */ +	int	my_proc;			/* rpc procedure # of the requesting process */ +}; + +struct mon_id { +	string	mon_name<SM_MAXSTRLEN>;		/* name of the site to be monitored */ +	struct my_id my_id; +}; + + +struct mon{ +	struct mon_id mon_id; +	opaque priv[16]; 		/* private information to store at monitor for requesting process */ +}; + + +/* + * state # of status monitor monitonically increases each time + * status of the site changes: + * an even number (>= 0) indicates the site is down and + * an odd number (> 0) indicates the site is up; + */ +struct sm_stat { +	int state;		/* state # of status monitor */ +}; + +enum res { +	stat_succ = 0,		/* status monitor agrees to monitor */ +	stat_fail = 1		/* status monitor cannot monitor */ +}; + +struct sm_stat_res { +	res res_stat; +	int state; +}; + +/*  + * structure of the status message sent back by the status monitor + * when monitor site status changes + */ +struct status { +	string mon_name<SM_MAXSTRLEN>; +	int state; +	opaque priv[16];		/* stored private information */ +}; diff --git a/lib/librpc/rpcsvc/spray.x b/lib/librpc/rpcsvc/spray.x new file mode 100644 index 000000000000..b242f0ac75d3 --- /dev/null +++ b/lib/librpc/rpcsvc/spray.x @@ -0,0 +1,84 @@ +/* @(#)spray.x	2.1 88/08/01 4.0 RPCSRC */ +/* @(#)spray.x 1.2 87/09/18 Copyr 1987 Sun Micro */ + +/* + * Sun RPC is a product of Sun Microsystems, Inc. and is provided for + * unrestricted use provided that this legend is included on all tape + * media and as a part of the software program in whole or part.  Users + * may copy or modify Sun RPC without charge, but are not authorized + * to license or distribute it to anyone else except as part of a product or + * program developed by the user. + *  + * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE + * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR + * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. + *  + * Sun RPC is provided with no support and without any obligation on the + * part of Sun Microsystems, Inc. to assist in its use, correction, + * modification or enhancement. + *  + * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE + * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC + * OR ANY PART THEREOF. + *  + * In no event will Sun Microsystems, Inc. be liable for any lost revenue + * or profits or other special, indirect and consequential damages, even if + * Sun has been advised of the possibility of such damages. + *  + * Sun Microsystems, Inc. + * 2550 Garcia Avenue + * Mountain View, California  94043 + */ + +/* + * Spray a server with packets + * Useful for testing flakiness of network interfaces + */ + +const SPRAYMAX = 8845;	/* max amount can spray */ + +/* + * GMT since 0:00, 1 January 1970 + */ +struct spraytimeval { +	unsigned int sec; +	unsigned int usec; +}; + +/* + * spray statistics + */ +struct spraycumul { +	unsigned int counter; +	spraytimeval clock; +}; + +/* + * spray data + */ +typedef opaque sprayarr<SPRAYMAX>; + +program SPRAYPROG { +	version SPRAYVERS { +		/* +		 * Just throw away the data and increment the counter +		 * This call never returns, so the client should always  +		 * time it out. +		 */ +		void +		SPRAYPROC_SPRAY(sprayarr) = 1; + +		/* +		 * Get the value of the counter and elapsed time  since +		 * last CLEAR. +		 */ +		spraycumul	 +		SPRAYPROC_GET(void) = 2; + +		/* +		 * Clear the counter and reset the elapsed time +		 */ +		void +		SPRAYPROC_CLEAR(void) = 3; +	} = 1; +} = 100012; diff --git a/lib/librpc/rpcsvc/yp.x b/lib/librpc/rpcsvc/yp.x new file mode 100644 index 000000000000..8fe70a270674 --- /dev/null +++ b/lib/librpc/rpcsvc/yp.x @@ -0,0 +1,291 @@ +/* @(#)yp.x	2.1 88/08/01 4.0 RPCSRC */ + +/* + * Sun RPC is a product of Sun Microsystems, Inc. and is provided for + * unrestricted use provided that this legend is included on all tape + * media and as a part of the software program in whole or part.  Users + * may copy or modify Sun RPC without charge, but are not authorized + * to license or distribute it to anyone else except as part of a product or + * program developed by the user. + *  + * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE + * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR + * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. + *  + * Sun RPC is provided with no support and without any obligation on the + * part of Sun Microsystems, Inc. to assist in its use, correction, + * modification or enhancement. + *  + * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE + * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC + * OR ANY PART THEREOF. + *  + * In no event will Sun Microsystems, Inc. be liable for any lost revenue + * or profits or other special, indirect and consequential damages, even if + * Sun has been advised of the possibility of such damages. + *  + * Sun Microsystems, Inc. + * 2550 Garcia Avenue + * Mountain View, California  94043 + */ + +/* + * Protocol description file for the Yellow Pages Service + */ + +const YPMAXRECORD = 1024; +const YPMAXDOMAIN = 64; +const YPMAXMAP = 64; +const YPMAXPEER = 64; + + +enum ypstat { +	YP_TRUE		=  1, +	YP_NOMORE	=  2, +	YP_FALSE	=  0, +	YP_NOMAP	= -1, +	YP_NODOM	= -2, +	YP_NOKEY	= -3, +	YP_BADOP	= -4, +	YP_BADDB	= -5, +	YP_YPERR	= -6, +	YP_BADARGS	= -7, +	YP_VERS		= -8 +}; + + +enum ypxfrstat { +	YPXFR_SUCC	=  1, +	YPXFR_AGE	=  2, +	YPXFR_NOMAP	= -1, +	YPXFR_NODOM	= -2, +	YPXFR_RSRC	= -3, +	YPXFR_RPC	= -4, +	YPXFR_MADDR	= -5, +	YPXFR_YPERR	= -6, +	YPXFR_BADARGS	= -7, +	YPXFR_DBM	= -8, +	YPXFR_FILE	= -9, +	YPXFR_SKEW	= -10, +	YPXFR_CLEAR	= -11, +	YPXFR_FORCE	= -12, +	YPXFR_XFRERR	= -13, +	YPXFR_REFUSED	= -14 +}; + + +typedef string domainname<YPMAXDOMAIN>; +typedef string mapname<YPMAXMAP>; +typedef string peername<YPMAXPEER>; +typedef opaque keydat<YPMAXRECORD>; +typedef opaque valdat<YPMAXRECORD>; + + +struct ypmap_parms { +	domainname domain;	 +	mapname map; +	unsigned int ordernum; +	peername peer; +}; + +struct ypreq_key { +	domainname domain; +	mapname map; +	keydat key; +}; + +struct ypreq_nokey { +	domainname domain;	 +	mapname map; +}; +	 +struct ypreq_xfr { +	ypmap_parms map_parms; +	unsigned int transid; +	unsigned int prog; +	unsigned int port; +}; + + +struct ypresp_val { +	ypstat stat; +	valdat val; +}; + +struct ypresp_key_val { +	ypstat stat; +	keydat key; +	valdat val; +}; + + +struct ypresp_master { +	ypstat stat;	 +	peername peer; +}; + +struct ypresp_order { +	ypstat stat; +	unsigned int ordernum; +}; + +union ypresp_all switch (bool more) { +case TRUE: +	ypresp_key_val val; +case FALSE: +	void; +}; + +struct ypresp_xfr { +	unsigned int transid; +	ypxfrstat xfrstat; +}; + +struct ypmaplist { +	mapname map; +	ypmaplist *next; +}; + +struct ypresp_maplist { +	ypstat stat; +	ypmaplist *maps; +}; + +enum yppush_status { +	YPPUSH_SUCC	=  1,	/* Success */ +	YPPUSH_AGE 	=  2,	/* Master's version not newer */ +	YPPUSH_NOMAP	= -1,	/* Can't find server for map */ +	YPPUSH_NODOM	= -2,	/* Domain not supported */ +	YPPUSH_RSRC	= -3,	/* Local resource alloc failure */ +	YPPUSH_RPC	= -4,	/* RPC failure talking to server */ +	YPPUSH_MADDR 	= -5,	/* Can't get master address */ +	YPPUSH_YPERR	= -6,	/* YP server/map db error */ +	YPPUSH_BADARGS	= -7,	/* Request arguments bad */ +	YPPUSH_DBM	= -8,	/* Local dbm operation failed */ +	YPPUSH_FILE	= -9,	/* Local file I/O operation failed */ +	YPPUSH_SKEW	= -10,	/* Map version skew during transfer */ +	YPPUSH_CLEAR	= -11,	/* Can't send "Clear" req to local ypserv */ +	YPPUSH_FORCE	= -12,	/* No local order number in map  use -f flag. */ +	YPPUSH_XFRERR 	= -13,	/* ypxfr error */ +	YPPUSH_REFUSED	= -14 	/* Transfer request refused by ypserv */ +}; + +struct yppushresp_xfr { +	unsigned transid; +	yppush_status status; +}; + +/* + * Response structure and overall result status codes.  Success and failure + * represent two separate response message types. + */ +  +enum ypbind_resptype { +	YPBIND_SUCC_VAL = 1,  +	YPBIND_FAIL_VAL = 2 +}; +  +struct ypbind_binding { +    opaque ypbind_binding_addr[4]; /* In network order */ +    opaque ypbind_binding_port[2]; /* In network order */ +};    + +union ypbind_resp switch (ypbind_resptype ypbind_status) { +case YPBIND_FAIL_VAL: +        unsigned ypbind_error; +case YPBIND_SUCC_VAL: +        ypbind_binding ypbind_bindinfo; +};      + +/* Detailed failure reason codes for response field ypbind_error*/ +  +const YPBIND_ERR_ERR    = 1;	/* Internal error */ +const YPBIND_ERR_NOSERV = 2;	/* No bound server for passed domain */ +const YPBIND_ERR_RESC   = 3;	/* System resource allocation failure */ +  +  +/* + * Request data structure for ypbind "Set domain" procedure. + */ +struct ypbind_setdom { +	domainname ypsetdom_domain; +	ypbind_binding ypsetdom_binding; +	unsigned ypsetdom_vers; +}; + + +/* + * YP access protocol + */ +program YPPROG { +	version YPVERS { +		void  +		YPPROC_NULL(void) = 0; + +		bool  +		YPPROC_DOMAIN(domainname) = 1;	 + +		bool +		YPPROC_DOMAIN_NONACK(domainname) = 2; + +		ypresp_val +		YPPROC_MATCH(ypreq_key) = 3; + +		ypresp_key_val  +		YPPROC_FIRST(ypreq_key) = 4; + +		ypresp_key_val  +		YPPROC_NEXT(ypreq_key) = 5; + +		ypresp_xfr +		YPPROC_XFR(ypreq_xfr) = 6; + +		void +		YPPROC_CLEAR(void) = 7; + +		ypresp_all +		YPPROC_ALL(ypreq_nokey) = 8; + +		ypresp_master +		YPPROC_MASTER(ypreq_nokey) = 9; + +		ypresp_order +		YPPROC_ORDER(ypreq_nokey) = 10; + +		ypresp_maplist  +		YPPROC_MAPLIST(domainname) = 11; +	} = 2; +} = 100004; + + +/* + * YPPUSHPROC_XFRRESP is the callback routine for result of YPPROC_XFR + */ +program YPPUSH_XFRRESPPROG { +	version YPPUSH_XFRRESPVERS { +		void +		YPPUSHPROC_NULL(void) = 0; + +		yppushresp_xfr	 +		YPPUSHPROC_XFRRESP(void) = 1; +	} = 1; +} = 0x40000000;	/* transient: could be anything up to 0x5fffffff */ + + +/* + * YP binding protocol + */ +program YPBINDPROG { +	version YPBINDVERS { +		void +		YPBINDPROC_NULL(void) = 0; +	 +		ypbind_resp +		YPBINDPROC_DOMAIN(domainname) = 1; + +		void +		YPBINDPROC_SETDOM(ypbind_setdom) = 2; +	} = 2; +} = 100007; + + diff --git a/lib/librpc/rpcsvc/yppasswd.x b/lib/librpc/rpcsvc/yppasswd.x new file mode 100644 index 000000000000..ad349adbfa30 --- /dev/null +++ b/lib/librpc/rpcsvc/yppasswd.x @@ -0,0 +1,63 @@ +/* @(#)yppasswd.x	2.1 88/08/01 4.0 RPCSRC */ +/* @(#)yppasswd.x 1.1 87/04/13 Copyr 1987 Sun Micro */ + +/* + * Sun RPC is a product of Sun Microsystems, Inc. and is provided for + * unrestricted use provided that this legend is included on all tape + * media and as a part of the software program in whole or part.  Users + * may copy or modify Sun RPC without charge, but are not authorized + * to license or distribute it to anyone else except as part of a product or + * program developed by the user. + *  + * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE + * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR + * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. + *  + * Sun RPC is provided with no support and without any obligation on the + * part of Sun Microsystems, Inc. to assist in its use, correction, + * modification or enhancement. + *  + * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE + * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC + * OR ANY PART THEREOF. + *  + * In no event will Sun Microsystems, Inc. be liable for any lost revenue + * or profits or other special, indirect and consequential damages, even if + * Sun has been advised of the possibility of such damages. + *  + * Sun Microsystems, Inc. + * 2550 Garcia Avenue + * Mountain View, California  94043 + */ + +/* + * YP password update protocol + * Requires unix authentication + */ +program YPPASSWDPROG { +	version YPPASSWDVERS { +		/* +		 * Update my passwd entry  +		 */ +		int +		YPPASSWDPROC_UPDATE(yppasswd) = 1; +	} = 1; +} = 100009; + + +struct passwd { +	string pw_name<>;	/* username */ +	string pw_passwd<>;	/* encrypted password */ +	int pw_uid;		/* user id */ +	int pw_gid;		/* group id */ +	string pw_gecos<>;	/* in real life name */ +	string pw_dir<>;	/* home directory */ +	string pw_shell<>;	/* default shell */ +}; + +struct yppasswd { +	string oldpass<>;	/* unencrypted old password */ +	passwd newpw;		/* new passwd entry */ +}; + + diff --git a/lib/librpc/secure_rpc/README b/lib/librpc/secure_rpc/README new file mode 100644 index 000000000000..b8a860ef2698 --- /dev/null +++ b/lib/librpc/secure_rpc/README @@ -0,0 +1,92 @@ +Export restriction prohibit us from including DES encryption routines in RPCSRC +4.0.  The main RPCSRC 4.0 hierarchy does not include DES Authentication, +however this directory contains the documentation and code used to build secure +rpc.  THIS DISTRIBUTION OF SECURE RPC NEEDS EXTENSIVE WORK BEFORE IT CAN BE +USED.  PLEASE READ THE PORTING GUIDLINES BELOW. + +HIERARCHY + +bin/ + +    This directory contains chkey and keylogin. These are user programs +    used to establish the credentials of an RPC user. + +demo/ +    The 'whoami' service is found here.  It can be used to test secure RPC. +    rpcgen is used to build the client and server. + +des/ + +    des_crypt.h defines the interfaces to cbc_crypt() and ecb_crypt(), +    the DES routines used by DES Authentication. +    des.h defines the desparams structure that is used internally by +    these routines.  Secure RPC expects it to be installed in +    /usr/include/sys. +    des_crypt.c defines the cbc_crypt() and ecb_crypt() routines.  These +    eventually call the routine _des_crypt(), which is *not* provided. +    des_soft.c contains the des_setparity() routine. + +doc/ + +    The document "nfs.secure.ms" is found here. It describes Secure +    RPC and Secure NFS. + +keyserv/ + +    This is an RPC based program that stores the private keys for +    users that are using secure RPC. + +man/ + +    Manual pages for the programs and library routines are found here. + +rpc/ + +    The routines in this directory should be integrated with the +    default rpc directory to make a single RPC library.  The Makefile +    found in this directory replaces the one in ../rpc.  Note: the file +    svc_auth.c in this directory replaces the one in ../rpc.  Also, the +    file ../rpc/rpc.h should be edited to include the file <rpc/des_auth.h> +    (it presently is commented out). + +PORTING GUIDELINES + +You will need to provide a DES encryption routine.  man/des_crypt.3 describes +the interface to ecb_crypt() and cbc_crypt() (secure RPC uses both modes).  The +des/ directory has the "front-end" for these routines in the des_crypt.c file. + +Since public key authentication systems require a network global data lookup +facility, this implementation uses Sun's Yellow Pages.  If your site does not +have Yellow Pages, you will have to modify the routines in rpc/publickey.c and +bin/chkey.c.  One possible approach is to replace the YP calls with code to +read the file /etc/publickey; this file would presumably be shared by all +secure RPC sites via NFS or some equivalent file sharing facility.  If you wish +to implement YP yourself, the RPCL (.x) protocol description file can be found +in ../rpcsvc/yp.x. + +The routines in rpc/ and keyserv/ assume that the file des/des_crypt.h +is installed in /usr/include (they include <des_crypt.h>).  The file +des/des_crypt.c assumes that des.h is installed in /usr/include/sys (it +include <sys/des.h>).  The des/ directory does not have a Makefile that +would install these header files, so you will either have to do this +by hand, or modify the routines to include the header files in a way suitable +for your site. + +While the programs in bin/ and keyserv/ can be built in place (assuming +the header files they include and the RPC library are available), the files +in rpc/ must be moved into ../rpc/, the main RPC library.  The Makefile and +svc_auth.c found in rpc/ will replace those found in ../rpc/.  You must also +edit ../rpc/rpc.h to include <rpc/des_auth.h>. + +OPERATION + +Please read the documentation and manual pages for information on how to +administer secure RPC. + +In the demo/ directory you'll find the 'whoami' service.  This service uses DES +Authentication, and can be used to check out secure RPC.  The client program, +'rme' takes a host as an argument.  This host must be running the keyserv +daemon and the 'whoami_svc' server.  The service returns the identity of the +client-user as known to the system on which the server is running.  This +information is only returned, however, if the client request has proper DES +credentials. diff --git a/lib/librpc/secure_rpc/bin/Makefile b/lib/librpc/secure_rpc/bin/Makefile new file mode 100644 index 000000000000..9d080187616d --- /dev/null +++ b/lib/librpc/secure_rpc/bin/Makefile @@ -0,0 +1,50 @@ +# +#	@(#)Makefile	2.1 88/08/10 4.0 RPCSRC +# +DESTDIR= +CFLAGS=	-O +RPCLIB= -lrpclib + +# C programs that live in the current directory and need explicit make lines. +# (make depend has special rules for these files) +# +NSTD=	chkey keylogin + +all:	${NSTD} + +chkey: chkey.c +	${CC} ${CFLAGS} -o chkey chkey.c -lrpcsvc -lmp ${RPCLIB} + +keylogin: keylogin.c +	${CC} ${CFLAGS} -o keylogin keylogin.c -lrpcsvc ${RPCLIB} + +install: +	-for i in ${NSTD}; do \ +		(install -s $$i ${DESTDIR}/usr/bin/$$i); done + +clean: +	rm -f a.out core *.s *.o +	rm -f ${NSTD} + +depend: +	for i in ${NSTD}; do \ +	    cc -M ${INCPATH} $$i.c | sed 's/\.o//' | \ +	    awk ' { if ($$1 != prev) \ +		{ if (rec != "") print rec; rec = $$0; prev = $$1; } \ +		else { if (length(rec $$2) > 78) { print rec; rec = $$0; } \ +		else rec = rec " " $$2 } } \ +		END { print rec } ' >> makedep; done +	echo '/^# DO NOT DELETE THIS LINE/+2,$$d' >eddep +	echo '$$r makedep' >>eddep +	echo 'w' >>eddep +	cp Makefile Makefile.bak +	ed - Makefile < eddep +	rm eddep makedep +	echo '# DEPENDENCIES MUST END AT END OF FILE' >> Makefile +	echo '# IF YOU PUT STUFF HERE IT WILL GO AWAY' >> Makefile +	echo '# see make depend above' >> Makefile + +# Files listed in ${NSTD} have explicit make lines given below. + +# DO NOT DELETE THIS LINE -- make depend uses it + diff --git a/lib/librpc/secure_rpc/bin/chkey.c b/lib/librpc/secure_rpc/bin/chkey.c new file mode 100644 index 000000000000..eefb34e606d5 --- /dev/null +++ b/lib/librpc/secure_rpc/bin/chkey.c @@ -0,0 +1,302 @@ +#ifndef lint +static char sccsid[] = 	"@(#)chkey.c	2.3 88/08/15 4.0 RPCSRC"; +#endif +/* + * Sun RPC is a product of Sun Microsystems, Inc. and is provided for + * unrestricted use provided that this legend is included on all tape + * media and as a part of the software program in whole or part.  Users + * may copy or modify Sun RPC without charge, but are not authorized + * to license or distribute it to anyone else except as part of a product or + * program developed by the user. + *  + * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE + * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR + * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. + *  + * Sun RPC is provided with no support and without any obligation on the + * part of Sun Microsystems, Inc. to assist in its use, correction, + * modification or enhancement. + *  + * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE + * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC + * OR ANY PART THEREOF. + *  + * In no event will Sun Microsystems, Inc. be liable for any lost revenue + * or profits or other special, indirect and consequential damages, even if + * Sun has been advised of the possibility of such damages. + *  + * Sun Microsystems, Inc. + * 2550 Garcia Avenue + * Mountain View, California  94043 + */ +/* + * Copyright (c) 1988 by Sun Microsystems, Inc. + */ + +/* + * Command to change one's public key in the public key database + */ +#include <stdio.h> +#include <rpc/rpc.h> +#include <rpc/key_prot.h> +#include <rpcsvc/ypclnt.h> +#include <sys/file.h> +#include <pwd.h> +#include <mp.h> + +extern char *getpass(); +extern char *index(); +extern char *crypt(); +extern char *sprintf(); +extern long random(); + +static char PKMAP[] = "publickey.byname"; +static char *domain; +struct passwd *ypgetpwuid(); + +main(argc, argv) +	int argc; +	char **argv; +{ +	char name[MAXNETNAMELEN+1]; +	char public[HEXKEYBYTES + 1]; +	char secret[HEXKEYBYTES + 1]; +	char crypt1[HEXKEYBYTES + KEYCHECKSUMSIZE + 1]; +	char crypt2[HEXKEYBYTES + KEYCHECKSUMSIZE + 1]; +	int status;	 +	char *pass; +	struct passwd *pw; +	char *master; +	int euid; +	int fd; +	int force; +	char *self; + +	self = argv[0]; +	force = 0; +	for (argc--, argv++; argc > 0 && **argv == '-'; argc--, argv++) { +		if (argv[0][2] != 0) { +			usage(self); +		} +		switch (argv[0][1]) { +		case 'f': +			force = 1; +			break; +		default: +			usage(self); +		} +	} +	if (argc != 0) { +		usage(self); +	} + +	(void)yp_get_default_domain(&domain); +	if (yp_master(domain, PKMAP, &master) != 0) { +		(void)fprintf(stderr,  +			"can't find master of publickey database\n"); +		exit(1); +	} + +	getnetname(name); +	(void)printf("Generating new key for %s.\n", name); + +	euid = geteuid(); +	if (euid != 0) { +		pw = ypgetpwuid(euid); +		if (pw == NULL) { +			(void)fprintf(stderr,  +				"No yp password found: can't change key.\n"); +			exit(1); +		} +	} else { +		pw = getpwuid(0); +		if (pw == NULL) { +			(void)fprintf(stderr,  +				"No password found: can't change key.\n"); +			exit(1); +		} +	} +	pass = getpass("Password:"); +	if (!force) { +		if (strcmp(crypt(pass, pw->pw_passwd), pw->pw_passwd) != 0) { +			(void)fprintf(stderr, "Invalid password.\n"); +			exit(1); +		} +	} + +	genkeys(public, secret, pass);	 + +	bcopy(secret, crypt1, HEXKEYBYTES); +	bcopy(secret, crypt1 + HEXKEYBYTES, KEYCHECKSUMSIZE); +	crypt1[HEXKEYBYTES + KEYCHECKSUMSIZE] = 0; +	xencrypt(crypt1, pass); + +	if (force) { +		bcopy(crypt1, crypt2, HEXKEYBYTES + KEYCHECKSUMSIZE + 1);	 +		xdecrypt(crypt2, getpass("Retype password:")); +		if (bcmp(crypt2, crypt2 + HEXKEYBYTES, KEYCHECKSUMSIZE) != 0 || +	    	    bcmp(crypt2, secret, HEXKEYBYTES) != 0) {	 +			(void)fprintf(stderr, "Password incorrect.\n"); +			exit(1); +		} +	} + +	(void)printf("Sending key change request to %s...\n", master); +	status = setpublicmap(name, public, crypt1); +	if (status != 0) { +		(void)printf("%s: unable to update yp database (%u): %s\n",  +			     self, status, yperr_string(status)); +		(void)printf("Perhaps %s is down?\n", master); +		exit(1); +	} +	(void)printf("Done.\n"); + +	if (key_setsecret(secret) < 0) { +		(void)printf("Unable to login with new secret key.\n"); +		exit(1); +	} +} + +usage(name) +	char *name; +{ +	(void)fprintf(stderr, "usage: %s [-f]\n", name); +	exit(1); +} + + +/* + * Generate a seed + */ +getseed(seed, seedsize, pass) +	char *seed; +	int seedsize; +	unsigned char *pass; +{ +	int i; +	int rseed; +	struct timeval tv; + +	(void)gettimeofday(&tv, (struct timezone *)NULL); +	rseed = tv.tv_sec + tv.tv_usec; +	for (i = 0; i < 8; i++) { +		rseed ^= (rseed << 8) | pass[i]; +	} +	srandom(rseed); + +	for (i = 0; i < seedsize; i++) { +		seed[i] = (random() & 0xff) ^ pass[i % 8]; +	} +} + + +/* + * Generate a random public/secret key pair + */ +genkeys(public, secret, pass) +	char *public; +	char *secret; +	char *pass; +{ +	int i; +  +#define BASEBITS	(8*sizeof(short) - 1) +#define BASE		(1 << BASEBITS) +  +	MINT *pk = itom(0); + 	MINT *sk = itom(0); +	MINT *tmp; +	MINT *base = itom(BASE); +	MINT *root = itom(PROOT); +	MINT *modulus = xtom(HEXMODULUS); +	short r; +	unsigned short seed[KEYSIZE/BASEBITS + 1]; +	char *xkey; + +	getseed((char *)seed, sizeof(seed), (unsigned char *)pass);	 +	for (i = 0; i < KEYSIZE/BASEBITS + 1; i++) { +		r = seed[i] % BASE; +		tmp = itom(r); +		mult(sk, base, sk); +		madd(sk, tmp, sk); +		mfree(tmp);   +	} +	tmp = itom(0); +	mdiv(sk, modulus, tmp, sk); +	mfree(tmp); +	pow(root, sk, modulus, pk);  +	xkey = mtox(sk);    +	adjust(secret, xkey); +	xkey = mtox(pk); +	adjust(public, xkey); +	mfree(sk); +	mfree(base); +	mfree(pk); +	mfree(root); +	mfree(modulus); +}  + +/* + * Adjust the input key so that it is 0-filled on the left + */ +adjust(keyout, keyin) +	char keyout[HEXKEYBYTES+1]; +	char *keyin; +{ +	char *p; +	char *s; + +	for (p = keyin; *p; p++)  +		; +	for (s = keyout + HEXKEYBYTES; p >= keyin; p--, s--) { +		*s = *p; +	} +	while (s >= keyout) { +		*s-- = '0'; +	} +} + +/* + * Set the entry in the public key map + */ +setpublicmap(name, public, secret) +	char *name; +	char *public; +	char *secret; +{ +	char pkent[1024]; +	u_int rslt; +	 +	(void)sprintf(pkent,"%s:%s", public, secret); +	rslt = yp_update(domain, PKMAP, YPOP_STORE,  +		name, strlen(name), pkent, strlen(pkent)); +	return (rslt); +} + +struct passwd * +ypgetpwuid(uid) +	int uid; +{ +	char uidstr[10]; +	char *val; +	int vallen; +	static struct passwd pw; +	char *p; + +	(void)sprintf(uidstr, "%d", uid); +	if (yp_match(domain, "passwd.byuid", uidstr, strlen(uidstr),  +		     &val, &vallen) != 0) { +		return (NULL); +	} +	p = index(val, ':'); +	if (p == NULL) {	 +		return (NULL); +	} +	pw.pw_passwd = p + 1; +	p = index(pw.pw_passwd, ':'); +	if (p == NULL) { +		return (NULL); +	} +	*p = 0; +	return (&pw); +} diff --git a/lib/librpc/secure_rpc/bin/keylogin.c b/lib/librpc/secure_rpc/bin/keylogin.c new file mode 100644 index 000000000000..0643f07eee9e --- /dev/null +++ b/lib/librpc/secure_rpc/bin/keylogin.c @@ -0,0 +1,66 @@ +#ifndef lint +static char sccsid[] = 	"@(#)keylogin.c	2.2 88/08/10 4.0 RPCSRC"; +#endif +/* + * Sun RPC is a product of Sun Microsystems, Inc. and is provided for + * unrestricted use provided that this legend is included on all tape + * media and as a part of the software program in whole or part.  Users + * may copy or modify Sun RPC without charge, but are not authorized + * to license or distribute it to anyone else except as part of a product or + * program developed by the user. + *  + * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE + * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR + * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. + *  + * Sun RPC is provided with no support and without any obligation on the + * part of Sun Microsystems, Inc. to assist in its use, correction, + * modification or enhancement. + *  + * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE + * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC + * OR ANY PART THEREOF. + *  + * In no event will Sun Microsystems, Inc. be liable for any lost revenue + * or profits or other special, indirect and consequential damages, even if + * Sun has been advised of the possibility of such damages. + *  + * Sun Microsystems, Inc. + * 2550 Garcia Avenue + * Mountain View, California  94043 + */ +/* + * Copyright (c) 1988 by Sun Microsystems, Inc. + */ + +/* + * Set secret key on local machine + */ +#include <stdio.h> +#include <rpc/rpc.h> +#include <rpc/key_prot.h> + +main(argc,argv) +	int argc; +	char *argv[]; +{ +	char fullname[MAXNETNAMELEN + 1]; +	char secret[HEXKEYBYTES + 1]; +	char *getpass(); + +	getnetname(fullname); +	if (! getsecretkey(fullname, secret, getpass("Password:"))) { +		fprintf(stderr, "Can't find %s's secret key\n", fullname); +		exit(1); +	} +	if (secret[0] == 0) { +		fprintf(stderr, "Password incorrect for %s\n", fullname); +		exit(1); +	} +	if (key_setsecret(secret) < 0) { +		fprintf(stderr, "Could not set %s's secret key\n", fullname); +		fprintf(stderr, "Maybe the keyserver is down?\n"); +		exit(1); +	} +	exit(0); +} diff --git a/lib/librpc/secure_rpc/demo/Makefile b/lib/librpc/secure_rpc/demo/Makefile new file mode 100644 index 000000000000..f1e62a7f6831 --- /dev/null +++ b/lib/librpc/secure_rpc/demo/Makefile @@ -0,0 +1,28 @@ +# +# @(#)Makefile	2.2 88/08/15 4.0 RPCSRC +# +BIN = whoami_svc rme +GEN = whoami_clnt.c whoami_svc.c whoami_xdr.c whoami.h +LIB = -lrpclib +#use this line on SunOS or NFSSRC-based systems. +#LIB = -lrpcsvc +RPCCOM = rpcgen + +all: $(BIN) + +$(GEN): whoami.x +	$(RPCCOM) whoami.x + +whoami_svc: whoami_proc.o whoami_svc.o whoami_xdr.o +	$(CC) -o $@ whoami_proc.o whoami_svc.o whoami_xdr.o $(LIB) + +rme: rme.o whoami_clnt.o whoami_xdr.o +	$(CC) -o $@ rme.o whoami_clnt.o whoami_xdr.o $(LIB) + +rme.o: rme.c whoami.h + +whoami_proc.o: whoami_proc.c whoami.h + +clean cleanup: +	rm -f $(GEN) *.o $(BIN) + diff --git a/lib/librpc/secure_rpc/demo/rme.c b/lib/librpc/secure_rpc/demo/rme.c new file mode 100644 index 000000000000..773eafaf5793 --- /dev/null +++ b/lib/librpc/secure_rpc/demo/rme.c @@ -0,0 +1,96 @@ +#if defined(LIBC_SCCS) && !defined(lint) +static char sccsid[] = 	"@(#)rme.c	2.3 88/09/09 4.0 RPCSRC"; +#endif +/* + * rme.c: secure identity verifier and reporter: client side + */ +#include <rpc/rpc.h> +#include <stdio.h> +#include "whoami.h" + +/* + * Before running this program, the user must have a key in the publickey + * database, and must have logged in with a password (or used keylogin). + * The user's machine and the server's machine must both be running keyserv. + */ + +main(argc, argv) +	int argc; +	char *argv[]; +{ +	CLIENT *cl; +	char *server; +	remote_identity *remote_me; +	name *servername; +	void *nullp; + +	if (argc != 2) { +		fprintf(stderr, "usage: %s host\n", argv[0]); +		exit(1); +	} + +	/* +	 * Remember what our command line argument refers to +	 */ +	server = argv[1]; + +	/* +	 * Create client "handle" used for calling WHOAMI on the +	 * server designated on the command line. We tell the rpc package +	 * to use the "udp" protocol when contacting the server. +	 */ +	cl = clnt_create(server, WHOAMI, WHOAMI_V1, "udp"); +	if (cl == NULL) { +		/* +		 * Couldn't establish connection with server. +		 * Print error message and die. +		 */ +		clnt_pcreateerror(server); +		exit(1); +	} +    /* +     * Get network identifier for server machine. +     */ +    servername = whoami_whoru_1(nullp, cl); +    if (servername == NULL) +    { +        fprintf(stderr, "Trouble communicating with %s\n", +            clnt_sperror(cl, server)); +        exit(1); +    } +    else if (*servername[0] == '\0') +    { +        fprintf(stderr, "Could not determine netname of WHOAMI server.\n"); +        exit(1); +    } +    printf("Server's netname is: %s\n", *servername); + +    /* +     * A wide window and no synchronization is used.  Client and server +     * clock must be with five minutes of each other. +     */ +    if ((cl->cl_auth = authdes_create(*servername, 300, NULL, NULL)) == NULL) +    { +        fprintf(stderr, "Could not establish DES credentials of netname %s\n", +            servername); +        exit(1); +    } + +    /* +     *  Find out who I am, in the server's point of view. +     */ +    remote_me = whoami_iask_1(nullp, cl); +    if (remote_me == NULL) +    { +        fprintf(stderr, "Trouble getting my identity from %s\n", +            clnt_sperror(cl, server)); +        exit(1); +    } +    /* +     * Print out my identity. +     */ +    printf("My remote user name: %s\n", remote_me->remote_username); +    printf("My remote real name: %s\n", remote_me->remote_realname); + +    exit(0); +} diff --git a/lib/librpc/secure_rpc/demo/whoami.x b/lib/librpc/secure_rpc/demo/whoami.x new file mode 100644 index 000000000000..041cd0a678ef --- /dev/null +++ b/lib/librpc/secure_rpc/demo/whoami.x @@ -0,0 +1,33 @@ +/* @(#)whoami.x	2.2 88/08/22 4.0 RPCSRC */ + +const WHOAMI_NGROUPS = 16; + +typedef string  name<MAXNETNAMELEN>; + +struct remote_identity { +    bool authenticated;     /* TRUE if the server authenticates us */ +    name remote_username;   /* login name */ +    name remote_realname;   /* gcos-field name (long name) */ +    int uid; +    int gid; +    int gids<WHOAMI_NGROUPS>; +}; + +program WHOAMI { +    version WHOAMI_V1 { +        /* +         * Report on the server's notion of the client's identity. +         * Will respond to AUTH_DES only. +         */ +        remote_identity +        WHOAMI_IASK(void) = 1; +        /* +         * Return server's netname. AUTH_NONE is okay. +         * This routine allows this server to be started under any uid, +         * and the client can ask it its netname for use in authdes_create(). +         */ +        name +        WHOAMI_WHORU(void) = 2; + +    } = 1; +} = 80955; diff --git a/lib/librpc/secure_rpc/demo/whoami_proc.c b/lib/librpc/secure_rpc/demo/whoami_proc.c new file mode 100644 index 000000000000..231d32228002 --- /dev/null +++ b/lib/librpc/secure_rpc/demo/whoami_proc.c @@ -0,0 +1,95 @@ +#if defined(LIBC_SCCS) && !defined(lint) +static char sccsid[] = 	"@(#)whoami_proc.c	2.3 89/07/11 4.0 RPCSRC"; +#endif +/* + * whoami_proc.c: secure identity verifier and reporter: server proc + */ +#include <sys/param.h> +#include <rpc/rpc.h> +#include <rpc/key_prot.h> +#include <pwd.h> +#include "whoami.h" + +extern char *strcpy(); + +/* + * Report on the server's notion of the client's identity. + */ +remote_identity * +whoami_iask_1(nullarg, rqstp) +    void           *nullarg; +	struct svc_req *rqstp; +{ +static remote_identity   whoisthem; +static char              username[MAXNETNAMELEN+1]; +static char              realname[MAXNETNAMELEN+1]; /* really gecos field */ +static int               grouplist[NGROUPS]; +    char                 publickey[HEXKEYBYTES+1]; + +    struct authdes_cred *des_cred; +    struct passwd *pwdent; + +    switch (rqstp->rq_cred.oa_flavor) +    { +    case AUTH_DES: +        whoisthem.remote_username = username; +        whoisthem.remote_realname = realname; +        whoisthem.gids.gids_val = grouplist; +        des_cred = (struct authdes_cred *) rqstp->rq_clntcred; +        /* +         * Check to see if the netname being used is in the public key +         * database (if not, reject this (potential) imposter). +         */ +        if (! getpublickey(des_cred->adc_fullname.name, publickey)) +        { +            svcerr_weakauth(rqstp->rq_xprt); +            return(NULL); +        } +        /* +         * Get the info that the client wants. +         */ +        if (! netname2user(des_cred->adc_fullname.name, &whoisthem.uid, +                &whoisthem.gid, &whoisthem.gids.gids_len, +                whoisthem.gids.gids_val)) +        {                           /* netname not found */ +            whoisthem.authenticated = FALSE; +            strcpy(whoisthem.remote_username, "nobody"); +            strcpy(whoisthem.remote_realname, "INTERLOPER!"); +            whoisthem.uid = -2; +            whoisthem.gid = -2; +            whoisthem.gids.gids_len = 0; +            return(&whoisthem); +        } +        /* else we found the netname */ +        whoisthem.authenticated = TRUE; +        pwdent = getpwuid(whoisthem.uid); +        strcpy(whoisthem.remote_username, pwdent->pw_name); +        strcpy(whoisthem.remote_realname, pwdent->pw_gecos); +        return(&whoisthem); +        break; +    case AUTH_UNIX: +    case AUTH_NULL: +    default: +        svcerr_weakauth(rqstp->rq_xprt); +        return(NULL); +    } +} + +/* + * Return server's netname. AUTH_NONE is valid. + * This routine allows this server to be started under any uid, + * and the client can ask us our netname for use in authdes_create(). + */ +name * +whoami_whoru_1(nullarg, rqstp) +    void           *nullarg; +	struct svc_req *rqstp; +{ +static name              whoru; +static char              servername[MAXNETNAMELEN+1]; + +    whoru = servername; +    getnetname(servername); + +    return(&whoru); +} diff --git a/lib/librpc/secure_rpc/des/des.h b/lib/librpc/secure_rpc/des/des.h new file mode 100644 index 000000000000..c237f23d2b82 --- /dev/null +++ b/lib/librpc/secure_rpc/des/des.h @@ -0,0 +1,68 @@ +/*  @(#)des.h	2.2 88/08/10 4.0 RPCSRC; from 2.7 88/02/08 SMI  */ +/* + * Sun RPC is a product of Sun Microsystems, Inc. and is provided for + * unrestricted use provided that this legend is included on all tape + * media and as a part of the software program in whole or part.  Users + * may copy or modify Sun RPC without charge, but are not authorized + * to license or distribute it to anyone else except as part of a product or + * program developed by the user. + *  + * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE + * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR + * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. + *  + * Sun RPC is provided with no support and without any obligation on the + * part of Sun Microsystems, Inc. to assist in its use, correction, + * modification or enhancement. + *  + * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE + * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC + * OR ANY PART THEREOF. + *  + * In no event will Sun Microsystems, Inc. be liable for any lost revenue + * or profits or other special, indirect and consequential damages, even if + * Sun has been advised of the possibility of such damages. + *  + * Sun Microsystems, Inc. + * 2550 Garcia Avenue + * Mountain View, California  94043 + */ +/* + * Generic DES driver interface + * Keep this file hardware independent! + * Copyright (c) 1986 by Sun Microsystems, Inc. + */ + +#define DES_MAXLEN 	65536	/* maximum # of bytes to encrypt  */ +#define DES_QUICKLEN	16	/* maximum # of bytes to encrypt quickly */ + +enum desdir { ENCRYPT, DECRYPT }; +enum desmode { CBC, ECB }; + +/* + * parameters to ioctl call + */ +struct desparams { +	u_char des_key[8];	/* key (with low bit parity) */ +	enum desdir des_dir;	/* direction */ +	enum desmode des_mode;	/* mode */ +	u_char des_ivec[8];	/* input vector */ +	unsigned des_len;	/* number of bytes to crypt */ +	union { +		u_char UDES_data[DES_QUICKLEN]; +		u_char *UDES_buf; +	} UDES; +#	define des_data UDES.UDES_data	/* direct data here if quick */ +#	define des_buf	UDES.UDES_buf	/* otherwise, pointer to data */ +}; + +/* + * Encrypt an arbitrary sized buffer + */ +#define	DESIOCBLOCK	_IOWR(d, 6, struct desparams) + +/*  + * Encrypt of small amount of data, quickly + */ +#define DESIOCQUICK	_IOWR(d, 7, struct desparams)  + diff --git a/lib/librpc/secure_rpc/des/des_crypt.c b/lib/librpc/secure_rpc/des/des_crypt.c new file mode 100644 index 000000000000..57a9e712f86b --- /dev/null +++ b/lib/librpc/secure_rpc/des/des_crypt.c @@ -0,0 +1,138 @@ +#ifndef lint +static char sccsid[] = "@(#)des_crypt.c	2.2 88/08/10 4.0 RPCSRC; from 1.13 88/02/08 SMI"; +#endif +/* + * Sun RPC is a product of Sun Microsystems, Inc. and is provided for + * unrestricted use provided that this legend is included on all tape + * media and as a part of the software program in whole or part.  Users + * may copy or modify Sun RPC without charge, but are not authorized + * to license or distribute it to anyone else except as part of a product or + * program developed by the user. + *  + * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE + * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR + * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. + *  + * Sun RPC is provided with no support and without any obligation on the + * part of Sun Microsystems, Inc. to assist in its use, correction, + * modification or enhancement. + *  + * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE + * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC + * OR ANY PART THEREOF. + *  + * In no event will Sun Microsystems, Inc. be liable for any lost revenue + * or profits or other special, indirect and consequential damages, even if + * Sun has been advised of the possibility of such damages. + *  + * Sun Microsystems, Inc. + * 2550 Garcia Avenue + * Mountain View, California  94043 + */ +/* + * des_crypt.c, DES encryption library routines + * Copyright (C) 1986, Sun Microsystems, Inc. + */ + +#include <sys/types.h> +#include <des_crypt.h> +#include <sys/des.h> + +/* + * To see if chip is installed  + */ +#define UNOPENED (-2) +static int g_desfd = UNOPENED; + + +/* + * Copy 8 bytes + */ +#define COPY8(src, dst) { \ +	register char *a = (char *) dst; \ +	register char *b = (char *) src; \ +	*a++ = *b++; *a++ = *b++; *a++ = *b++; *a++ = *b++; \ +	*a++ = *b++; *a++ = *b++; *a++ = *b++; *a++ = *b++; \ +} +  +/* + * Copy multiple of 8 bytes + */ +#define DESCOPY(src, dst, len) { \ +	register char *a = (char *) dst; \ +	register char *b = (char *) src; \ +	register int i; \ +	for (i = (int) len; i > 0; i -= 8) { \ +		*a++ = *b++; *a++ = *b++; *a++ = *b++; *a++ = *b++; \ +		*a++ = *b++; *a++ = *b++; *a++ = *b++; *a++ = *b++; \ +	} \ +} + +/* + * CBC mode encryption + */ +cbc_crypt(key, buf, len, mode, ivec) +	char *key; +	char *buf; +	unsigned len; +	unsigned mode; +	char *ivec;	 +{ +	int err; +	struct desparams dp; + +	dp.des_mode = CBC; +	COPY8(ivec, dp.des_ivec); +	err = common_crypt(key, buf, len, mode, &dp); +	COPY8(dp.des_ivec, ivec); +	return(err); +} + + +/* + * ECB mode encryption + */ +ecb_crypt(key, buf, len, mode) +	char *key; +	char *buf; +	unsigned len; +	unsigned mode; +{ +	struct desparams dp; + +	dp.des_mode = ECB;	 +	return(common_crypt(key, buf, len, mode, &dp)); +} + + + +/* + * Common code to cbc_crypt() & ecb_crypt() + */ +static +common_crypt(key, buf, len, mode, desp)	 +	char *key;	 +	char *buf; +	register unsigned len; +	unsigned mode; +	register struct desparams *desp; +{ +	register int desdev; +	register int res; + +	if ((len % 8) != 0 || len > DES_MAXDATA) { +		return(DESERR_BADPARAM); +	} +	desp->des_dir = +		((mode & DES_DIRMASK) == DES_ENCRYPT) ? ENCRYPT : DECRYPT; + +	desdev = mode & DES_DEVMASK; +	COPY8(key, desp->des_key); +	/*  +	 * software +	 */ +	if (!_des_crypt(buf, len, desp)) { +		return (DESERR_HWERROR); +	} +	return(desdev == DES_SW ? DESERR_NONE : DESERR_NOHWDEVICE); +} diff --git a/lib/librpc/secure_rpc/des/des_crypt.h b/lib/librpc/secure_rpc/des/des_crypt.h new file mode 100644 index 000000000000..d21d095b7155 --- /dev/null +++ b/lib/librpc/secure_rpc/des/des_crypt.h @@ -0,0 +1,101 @@ +/* + * @(#)des_crypt.h	2.1 88/08/11 4.0 RPCSRC;	from 1.4 88/02/08 (C) 1986 SMI + * + * des_crypt.h, des library routine interface + * Copyright (C) 1986, Sun Microsystems, Inc. + */ +/* + * Sun RPC is a product of Sun Microsystems, Inc. and is provided for + * unrestricted use provided that this legend is included on all tape + * media and as a part of the software program in whole or part.  Users + * may copy or modify Sun RPC without charge, but are not authorized + * to license or distribute it to anyone else except as part of a product or + * program developed by the user. + *  + * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE + * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR + * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. + *  + * Sun RPC is provided with no support and without any obligation on the + * part of Sun Microsystems, Inc. to assist in its use, correction, + * modification or enhancement. + *  + * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE + * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC + * OR ANY PART THEREOF. + *  + * In no event will Sun Microsystems, Inc. be liable for any lost revenue + * or profits or other special, indirect and consequential damages, even if + * Sun has been advised of the possibility of such damages. + *  + * Sun Microsystems, Inc. + * 2550 Garcia Avenue + * Mountain View, California  94043 + */ +#define DES_MAXDATA 8192	/* max bytes encrypted in one call */ +#define DES_DIRMASK (1 << 0) +#define DES_ENCRYPT (0*DES_DIRMASK)	/* Encrypt */ +#define DES_DECRYPT (1*DES_DIRMASK)	/* Decrypt */ + + +#define DES_DEVMASK (1 << 1) +#define	DES_HW (0*DES_DEVMASK)	/* Use hardware device */  +#define DES_SW (1*DES_DEVMASK)	/* Use software device */ + + +#define DESERR_NONE 0	/* succeeded */ +#define DESERR_NOHWDEVICE 1	/* succeeded, but hw device not available */ +#define DESERR_HWERROR 2	/* failed, hardware/driver error */ +#define DESERR_BADPARAM 3	/* failed, bad parameter to call */ + +#define DES_FAILED(err) \ +	((err) > DESERR_NOHWDEVICE) + +/* + * cbc_crypt() + * ecb_crypt() + * + * Encrypt (or decrypt) len bytes of a buffer buf. + * The length must be a multiple of eight. + * The key should have odd parity in the low bit of each byte. + * ivec is the input vector, and is updated to the new one (cbc only). + * The mode is created by oring together the appropriate parameters. + * DESERR_NOHWDEVICE is returned if DES_HW was specified but + * there was no hardware to do it on (the data will still be + * encrypted though, in software). + */ + + +/* + * Cipher Block Chaining mode + */ +cbc_crypt(/* key, buf, len, mode, ivec */); /* +	char *key;	 +	char *buf; +	unsigned len; +	unsigned mode; +	char *ivec;	 +*/  + + +/* + * Electronic Code Book mode + */ +ecb_crypt(/* key, buf, len, mode */); /* +	char *key;	 +	char *buf; +	unsigned len; +	unsigned mode; +*/ + + +#ifndef KERNEL +/*  + * Set des parity for a key. + * DES parity is odd and in the low bit of each byte + */ +void +des_setparity(/* key */); /* +	char *key;	 +*/ +#endif diff --git a/lib/librpc/secure_rpc/des/des_soft.c b/lib/librpc/secure_rpc/des/des_soft.c new file mode 100644 index 000000000000..01dd7f280b2f --- /dev/null +++ b/lib/librpc/secure_rpc/des/des_soft.c @@ -0,0 +1,67 @@ +#if !defined(lint) && defined(SCCSIDS) +static char sccsid[] = "@(#)des_soft.c	2.2 88/08/10 4.0 RPCSRC; from 1.13 88/02/08 SMI"; +#endif +/* + * Sun RPC is a product of Sun Microsystems, Inc. and is provided for + * unrestricted use provided that this legend is included on all tape + * media and as a part of the software program in whole or part.  Users + * may copy or modify Sun RPC without charge, but are not authorized + * to license or distribute it to anyone else except as part of a product or + * program developed by the user. + *  + * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE + * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR + * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. + *  + * Sun RPC is provided with no support and without any obligation on the + * part of Sun Microsystems, Inc. to assist in its use, correction, + * modification or enhancement. + *  + * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE + * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC + * OR ANY PART THEREOF. + *  + * In no event will Sun Microsystems, Inc. be liable for any lost revenue + * or profits or other special, indirect and consequential damages, even if + * Sun has been advised of the possibility of such damages. + *  + * Sun Microsystems, Inc. + * 2550 Garcia Avenue + * Mountain View, California  94043 + */ +/* + * Table giving odd parity in the low bit for ASCII characters + */ +static char partab[128] = { +	0x01, 0x01, 0x02, 0x02, 0x04, 0x04, 0x07, 0x07, +	0x08, 0x08, 0x0b, 0x0b, 0x0d, 0x0d, 0x0e, 0x0e, +	0x10, 0x10, 0x13, 0x13, 0x15, 0x15, 0x16, 0x16, +	0x19, 0x19, 0x1a, 0x1a, 0x1c, 0x1c, 0x1f, 0x1f, +	0x20, 0x20, 0x23, 0x23, 0x25, 0x25, 0x26, 0x26, +	0x29, 0x29, 0x2a, 0x2a, 0x2c, 0x2c, 0x2f, 0x2f, +	0x31, 0x31, 0x32, 0x32, 0x34, 0x34, 0x37, 0x37, +	0x38, 0x38, 0x3b, 0x3b, 0x3d, 0x3d, 0x3e, 0x3e, +	0x40, 0x40, 0x43, 0x43, 0x45, 0x45, 0x46, 0x46, +	0x49, 0x49, 0x4a, 0x4a, 0x4c, 0x4c, 0x4f, 0x4f, +	0x51, 0x51, 0x52, 0x52, 0x54, 0x54, 0x57, 0x57, +	0x58, 0x58, 0x5b, 0x5b, 0x5d, 0x5d, 0x5e, 0x5e, +	0x61, 0x61, 0x62, 0x62, 0x64, 0x64, 0x67, 0x67, +	0x68, 0x68, 0x6b, 0x6b, 0x6d, 0x6d, 0x6e, 0x6e, +	0x70, 0x70, 0x73, 0x73, 0x75, 0x75, 0x76, 0x76, +	0x79, 0x79, 0x7a, 0x7a, 0x7c, 0x7c, 0x7f, 0x7f, +}; + +/* + * Add odd parity to low bit of 8 byte key + */ +void +des_setparity(p) +	char *p; +{ +	int i; + +	for (i = 0; i < 8; i++) { +		*p = partab[*p & 0x7f]; +		p++; +	} +} diff --git a/lib/librpc/secure_rpc/doc/Makefile b/lib/librpc/secure_rpc/doc/Makefile new file mode 100644 index 000000000000..3cfbe9efef81 --- /dev/null +++ b/lib/librpc/secure_rpc/doc/Makefile @@ -0,0 +1,40 @@ +# +# @(#)Makefile	2.1 88/08/10 4.0 RPCSRC +# +# +TROFF=	ditroff +TOPTS=  -t +NROFF=	nroff +NOPTS= +PIC=	pic +TBL=	tbl +EQN=	eqn + +SRC=	 nfs.secure.ms + +all default: all.nroff + +install:	all.nroff +	@echo "Nothing installed." + +all.nroff:	${SRC} +	${TBL} ${SRC} | ${EQN} | ${NROFF} ${NOPTS} -ms >all.nroff + +all.troff:	${SRC} +	${TBL} ${SRC} | ${PIC} | ${EQN} | ${TROFF} ${TOPTS} -ms >all.troff + +# + +nfs.secure.nroff: nfs.secure.ms +	${TBL} nfs.secure.ms | ${EQN} | ${NROFF} ${NOPTS} -ms >nfs.secure.nroff + +nfs.secure.troff:	nfs.secure.ms +	${TBL} nfs.secure.ms|${PIC}|${EQN}| ${TROFF} ${TOPTS} -ms >nfs.secure.troff + +clean: +	rm -f *.nroff *.troff + +spell:	${SRC} +	@for i in ${SRC}; do \ +		echo $$i; spell $$i | sort | comm -23 - spell.ok > $$i.spell; \ +	done diff --git a/lib/librpc/secure_rpc/doc/nfs.secure.ms b/lib/librpc/secure_rpc/doc/nfs.secure.ms new file mode 100644 index 000000000000..247679018ae3 --- /dev/null +++ b/lib/librpc/secure_rpc/doc/nfs.secure.ms @@ -0,0 +1,934 @@ +.\" Must use  --  pic tbl eqn  --   with this one. +.\" +.\" @(#)nfs.secure.ms	2.2 88/08/09 4.0 RPCSRC +.de BT +.if \\n%=1 .tl ''- % -'' +.. +.ND +.\" prevent excess underlining in nroff +.if n .fp 2 R +.OH 'Secure Networking''Page %' +.EH 'Page %''Secure Networking' +.if \\n%=1 .bp +.EQ +delim $$ +gsize 11 +.EN +.SH +\&Secure Networking +.nr OF 1 +.IX "security" "of networks" "" "" PAGE START +.IX "network security" "" "" "" PAGE START +.IX "NFS security" "" "" "" PAGE START +.LP +RPCSRC 4.0 includes an authentication system +that greatly improves the security of network environments. +The system is general enough to be used by other +.UX +and non-UNIX systems. +The system uses DES encryption and public key cryptography +to authenticate both users and machines in the network. +(DES stands for Data Encryption Standard.) +.LP +Public key cryptography is a cipher system that involves two keys: +one public and the other private. +The public key is published, while the private key is not; +the private (or secret) key is used to encrypt and decrypt data. +Sun's system differs from some other public key cryptography systems +in that the public and secret keys are used to generate a common key, +which is used in turn to create a DES key. +DES is relatively fast, +and on Sun Workstations, +optional hardware is available to make it even faster. +.# +.NH 0 +\&Administering Secure RPC +.IX "administering secure RPC" +.IX "security" "RPC administration" +.LP +This section describes what the system administrator must do +in order to use secure networking. +.IP 1 +RPCSRC now includes the +.I /etc/publickey +.IX "etc/publickey" "" "\&\fI/etc/publickey\fP" +database, which should contain three fields for each user: +the user's netname, a public key, and an encrypted secret key. +The corresponding Yellow Pages map is available to YP clients as +.I publickey.byname +but the database should reside only on the YP master.  Make sure +.I /etc/netid +exists on the YP master server. +As normally installed, the only user is +.I nobody . +This is convenient administratively, +because users can establish their own public keys using +.I chkey (1) +.IX "chkey command" "" "\&\fIchkey\fP command" +without administrator intervention. +For even greater security, +the administrator can establish public keys for everyone using +.I newkey (8). +.IX "newkey command" "" "\&\fInewkey\fP command" +Note that the Yellow Pages take time to propagate a new map, +so it's a good idea for users to run +.I chkey , +or for the administrator to run +.I newkey , +just before going home for the night. +.IP 2 +Verify that the +.I keyserv (8c) +.IX "keyserv daemon" "" "\&\fIkeyserv\fP daemon" +daemon was started by +.I /etc/rc.local +and is still running. +This daemon performs public key encryption +and stores the private key (encrypted, of course) in +.I /etc/keystore : +.DS +% \fBps aux | grep keyserv\fP +root   1354  0.0  4.1  128  296 p0 I  Oct 15 0:13 keyserv +.DE +When users log in with +.I login  +.IX "login command" "" "\&\fIlogin\fP command" +or remote log in with +.I rlogin , +these programs use the typed password to decrypt the secret key stored in +.I /etc/publickey . +This becomes the private key, and gets passed to the +.I keyserv  +daemon. +If users don't type a password for +.I login  +or +.I rlogin , +either because their password field is empty +or because their machine is in the +.I hosts\fR.\fPequiv  +.IX "etc/hosts.equiv" "" "\&\fI/etc/hosts.equiv\fP" +file of the remote host, +they can still place a private key in +.I /etc/keystore  +by invoking the +.I keylogin (1) +.IX "keylogin command" "" "\&\fIkeylogin\fP command" +program. +Administrators should take care not to delete +.I /etc/keystore  +and +.I /etc/.rootkey  +(the latter file contains the private key for +.I root ). +.IP 3 +When you reinstall, move, or upgrade a machine, save +.I /etc/keystore  +and +.I /etc/.rootkey  +along with everything else you normally save. +.LP +.LP +Note that if you +.I login , +.I rlogin , +or +.I telnet  +to another machine, are asked for your password, and type it correctly, +you've given away access to your own account. +This is because your secret key is now stored in +.I /etc/keystore +on that remote machine. +This is only a concern if you don't trust the remote machine. +If this is the case, +don't ever log in to a remote machine if it asks for your password. +Instead, use NFS to remote mount the files you're looking for. +At this point there is no +.I keylogout  +command, even though there should be. +.LP +The remainder of this chapter discusses the theory of secure networking, +and is useful as a background for both users and administrators. +.# +.NH 1 +\&Security Shortcomings of NFS +.IX "security" "shortcomings of NFS" +.LP +Sun's Remote Procedure Call (RPC) mechanism has proved to be a very  +powerful primitive for building network services. +The most well-known of these services is the Network File System (NFS), +a service that provides transparent file-sharing +between heterogeneous machine architectures and operating systems. +The NFS is not without its shortcomings, however.  +Currently, an NFS server authenticates a file request by authenticating the +machine making the request, but not the user.  +On NFS-based filesystems, it is a simple matter of running +.I su  +.IX "su command" "" "\&\fIsu\fP command" +to impersonate the rightful owner of a file. +But the security weaknesses of the NFS are nothing new.  +The familiar command +.I rlogin  +is subject to exactly the same attacks as the NFS +because it uses the same kind of authentication.  +.LP +A common solution to network security problems +is to leave the solution to each application. +A far better solution is to put authentication at the RPC level. +The result is a standard authentication system +that covers all RPC-based applications, +such as the NFS and the Yellow Pages (a name-lookup service). +Our system allows the authentication of users as well as machines. +The advantage of this is that it makes a network environment +more like the older time-sharing environment. +Users can log in on any machine, +just as they could log in on any terminal.  +Their login password is their passport to network security. +No knowledge of the underlying authentication system is required. +Our goal was a system that is as secure and easy to use +as a time-sharing system.  +.LP +Several remarks are in order.  Given +.I root  +access and a good knowledge of network programming, +anyone is capable of injecting arbitrary data into the network, +and picking up any data from the network. +However, on a local area network, no machine is capable of packet smashing \(en +capturing packets before they reach their destination, changing the contents,  +then sending packets back on their original course \(en +because packets reach all machines, including the server, at the same time. +Packet smashing is possible on a gateway, though, +so make sure you trust all gateways on the network. +The most dangerous attacks are those involving the injection of data, +such as impersonating a user by generating the right packets, +or recording conversations and replaying them later. +These attacks affect data integrity. +Attacks involving passive eavesdropping \(en +merely listening to network traffic without impersonating anybody \(en +are not as dangerous, since data integrity had not been compromised. +Users can protect the privacy of sensitive information +by encrypting data that goes over the network. +It's not easy to make sense of network traffic, anyway. +.# +.NH 1 +\&RPC Authentication +.IX "RPC authentication" +.IX "authentication" "RPC" +.LP +RPC is at the core of the new network security system. +To understand the big picture, +it's necessary to understand how authentication works in RPC. +RPC's authentication is open-ended:  +a variety of authentication systems may be plugged into it +and may coexist on the network. +Currently, we have two: UNIX and DES.  +UNIX authentication is the older, weaker system; +DES authentication is the new system discussed in this chapter. +Two terms are important for any RPC authentication system: +.I credentials +and +.I verifiers . +Using ID badges as an example, the credential is what identifies a person: +a name, address, birth date, etc. +The verifier is the photo attached to the badge: +you can be sure the badge has not been stolen by checking the photo  +on the badge against the person carrying it. +In RPC, things are similar. +The client process sends both a credential and a verifier  +to the server with each RPC request. +The server sends back only a verifier, +since the client already knows the server's credentials. +.# +.NH 2 +\&UNIX Authentication +.IX "UNIX authentication" +.IX "authentication" "UNIX" +.LP +UNIX authentication was used by most of Sun's original network services. +The credentials contain the client's machine-name,  +.I uid , +.I gid , +and group-access-list. +The verifier contains \fBnothing\fP! +There are two problems with this system. +The glaring problem is the empty verifier, +which makes it easy to cook up the right credential using +.I hostname  +.IX "hostname command" "" "\&\fIhostname\fP command" +and +.I su . +.IX "su command" "" "\&\fIsu\fP command" +If you trust all root users in the network, this is not really a problem. +But many networks \(en especially at universities \(en are not this secure. +The NFS tries to combat deficiencies in UNIX authentication  +by checking the source Internet address of +.I mount  +requests as a verifier of the +.I hostname  +field, and accepting requests only from privileged Internet ports. +Still, it is not difficult to circumvent these measures,  +and NFS really has no way to verify the user-ID. +.LP +The other problem with UNIX authentication appears in the name UNIX. +It is unrealistic to assume that all machines on a network +will be UNIX machines. +The NFS works with MS-DOS and VMS machines, +but UNIX authentication breaks down when applied to them. +For instance, MS-DOS doesn't even have a notion of different user IDs. +.LP +Given these shortcomings, +it is clear what is needed in a new authentication system: +operating system independent credentials, and secure verifiers. +This is the essence of DES authentication discussed below. +.# +.NH 2 +\&DES Authentication +.IX "DES authentication" +.IX "authentication" "DES" +.LP +The security of DES authentication is based on +a sender's ability to encrypt the current time, +which the receiver can then decrypt and check against its own clock. +The timestamp is encrypted with DES. +Two things are necessary for this scheme to work: +1) the two agents must agree on what the current time is, and +2) the sender and receiver must be using the same encryption key. +.LP +If a network has time synchronization (Berkeley's TEMPO for example),  +then client/server time synchronization is performed automatically. +However, if this is not available, +timestamps can be computed using the server's time instead of network time. +In order to do this, the client asks the server what time it is, +before starting the RPC session, +then computes the time difference between its own clock and the server's. +This difference is used to offset the client's clock when computing timestamps. +If the client and server clocks get out of sync +to the point where the server begins rejecting the client's requests, +the DES authentication system just resynchronizes with the server. +.LP +Here's how the client and server arrive at the same encryption key. +When a client wishes to talk to a server, it generates at random  +a key to be used for encrypting the timestamps (among other things).  +This key is known as the +.I "conversation key, CK." +The client encrypts the conversation key using a public key scheme, +and sends it to the server in its first transaction. +This key is the only thing that is ever encrypted with public key cryptography. +The particular scheme used is described further on in this chapter. +For now, suffice to say that for any two agents A and B, +there is a DES key $K sub AB$ that only A and B can deduce. +This key is known as the +.I "common key," +$K sub AB$. +.EQ +gsize 10 +.EN +.ne 1i +.PS +.in +.7i +circlerad=.4 +boxht=.2 +boxwid=1.3 +circle "\s+9A\s-9" "(client)" at 0,1.2 +circle "\s+9B\s-9" "(server)" at 5.1,1.2 +line invis at .5,2 ; box invis "\fBCredential\fP"; line invis; +	box invis "\fBVerifier\fP" +arrow at .5,1.7; box "$A, K sub AB (CK), CK(win)$"; arrow; +	box "$CK(t sub 1 ), CK(win + 1)$"; arrow +arrow <- at .5,1.4; line right 1.3; line; +	box "$CK(t sub 1 - 1), ID$"; arrow <- +arrow at .5,1; box "ID"; arrow; +	box "$CK(t sub 2 )$"; arrow +arrow <- at .5,.7; line right 1.3; line; +	box "$CK(t sub 2 - 1), ID$"; arrow <- +arrow at .5,.3; box "ID"; arrow; +	box "$CK(t sub n )$"; arrow +arrow <- at .5,0; line right 1.3; line; +	box "$CK(t sub n - 1), ID$"; arrow <- +.PE +.EQ +gsize 11 +.EN +.in -.7i +.LP +The figure above illustrates the authentication protocol in more detail, +describing client A talking to server B. +A term of the form $K(x)$ means $x$ encrypted with the DES key $K$. +Examining the figure, you can see that for its first request, +the client's credential contains three things:  +its name $A$, the conversation key $CK$ encrypted with the common key  +$K sub AB$, and a thing called $win$ (window) encrypted with $CK$. +What the window says to the server, in effect, is this: +.LP +.I +I will be sending you many credentials in the future, +but there may be crackers sending them too, +trying to impersonate me with bogus timestamps. +When you receive a timestamp, check to see if your current time +is somewhere between the timestamp and the timestamp plus the window. +If it's not, please reject the credential.  +.LP +For secure NFS filesystems, the window currently defaults to 30 minutes. +The client's verifier in the first request contains the encrypted timestamp +and an encrypted verifier of the specified window, $win + 1$.  +The reason this exists is the following. +Suppose somebody wanted to impersonate A by writing a program +that instead of filling in the encrypted fields of the credential and verifier, +just stuffs in random bits. +The server will decrypt CK into some random DES key, +and use it to decrypt the window and the timestamp. +These will just end up as random numbers. +After a few thousand trials, there is a good chance +that the random window/timestamp pair will pass the authentication system. +The window verifier makes guessing the right credential much more difficult. +.LP +After authenticating the client, +the server stores four things into a credential table: +the client's name A, the conversation key $CK$, the window, and the timestamp. +The reason the server stores the first three things should be clear: +it needs them for future use. +The reason for storing the timestamp is to protect against replays. +The server will only accept timestamps +that are chronologically greater than the last one seen, +so any replayed transactions are guaranteed to be rejected. +The server returns to the client in its verifier an index ID +into its credential table, plus the client's timestamp minus one, +encrypted by $CK$. +The client knows that only the server could have sent such a verifier, +since only the server knows what timestamp the client sent. +The reason for subtracting one from it is to insure that it is invalid +and cannot be reused as a client verifier. +.LP +The first transaction is rather complicated, +but after this things go very smoothly. +The client just sends its ID and an encrypted timestamp to the server, +and the server sends back the client's timestamp minus one, +encrypted by $CK$. +.# +.NH 1 +\&Public Key Encryption +.IX "public key encryption" +.LP +The particular public key encryption scheme Sun uses +is the Diffie-Hellman method. +The way this algorithm works is to generate a +.I "secret key" +$SK sub A$ at random +and compute a +.I "public key" +$PK sub A$ using the following formula +($PK$ and $SK$ are 192 bit numbers and \(*a is a well-known constant): +.EQ +PK sub A ~ = ~ alpha sup {SK sub A} +.EN +Public key $PK sub A$ is stored in a public directory, +but secret key $SK sub A$ is kept private. +Next, $PK sub B$ is generated from $SK sub B$ in the same manner as above. +Now common key $K sub AB$ can be derived as follows: +.EQ +K sub AB ~ = ~ PK sub B sup {SK sub A} ~ = ~ +( alpha sup {SK sub B} ) sup {SK sub A} ~ = ~ +alpha sup {( SK sub A SK sub B )} +.EN +Without knowing the client's secret key, +the server can calculate the same common key $K sub AB$ +in a different way, as follows: +.EQ +K sub AB ~ = ~ PK sub A sup {SK sub B} ~ = ~ +( alpha sup {SK sub A} ) sup {SK sub B} ~ = ~ +alpha sup {( SK sub A SK sub B )} +.EN +Notice that nobody else but the server and client can calculate $K sub AB$, +since doing so requires knowing either one secret key or the other. +All of this arithmetic is actually computed modulo $M$, +which is another well-known constant. +It would seem at first that somebody could guess your secret key +by taking the logarithm of your public one,  +but $M$ is so large that this is a computationally infeasible task. +To be secure, $K sub AB$ has too many bits to be used as a DES key, +so 56 bits are extracted from it to form the DES key. +.LP +Both the public and the secret keys +are stored indexed by netname in the Yellow Pages map +.I publickey.byname +the secret key is DES-encrypted with your login password. +When you log in to a machine, the +.I login  +program grabs your encrypted secret key, +decrypts it with your login password, +and gives it to a secure local keyserver to save +for use in future RPC transactions. +Note that ordinary users do not have to be aware of  +their public and secret keys. +In addition to changing your login password, the +.I yppasswd  +.IX "yppasswd command" "" "\&\fIyppasswd\fP command" +program randomly generates a new public/secret key pair as well. +.LP +The keyserver +.I keyserv (8c) +.IX "keyserv daemon" "" "\&\fIkeyserv\fP daemon" +is an RPC service local to each machine +that performs all of the public key operations, +of which there are only three.  They are: +.DS +setsecretkey(secretkey) +encryptsessionkey(servername, des_key) +decryptsessionkey(clientname, des_key) +.DE +.I setsecretkey() +tells the keyserver to store away your secret key $SK sub A$ for future use; +it is normally called by +.I login . +The client program calls +.I encryptsessionkey() +to generate the encrypted conversation key +that is passed in the first RPC transaction to a server. +The keyserver looks up +.I servername 's +public key and combines it with the client's secret key (set up by a previous +.I setsecretkey() +call) to generate the key that encrypts +.I des_key . +The server asks the keyserver to decrypt the conversation key by calling +.I decryptsessionkey(). +Note that implicit in these procedures is the name of caller, +who must be authenticated in some manner. +The keyserver cannot use DES authentication to do this, +since it would create deadlock.  +The keyserver solves this problem by storing the secret keys by +.I uid , +and only granting requests to local root processes. +The client process then executes a +.I setuid  +process, owned by root, which makes the request on the part of the client, +telling the keyserver the real +.I uid  +of the client.  Ideally, the three operations described above +would be system calls, and the kernel would talk to the keyserver directly, +instead of executing the +.I setuid  +program. +.# +.NH 1 +\&Naming of Network Entities +.IX "naming of network entities" +.IX "network naming" +.LP +The old UNIX authentication system has a few problems when it comes to naming. +Recall that with UNIX authentication, +the name of a network entity is basically the +.I uid . +These +.I uid s +are assigned per Yellow Pages naming domain, +which typically spans several machines. +We have already stated one problem with this system, +that it is too UNIX system oriented,  +but there are two other problems as well. +One is the problem of +.I uid  +clashes when domains are linked together. +The other problem is that the super-user (with +.I uid  +of 0) should not be assigned on a per-domain basis,  +but rather on a per-machine basis. +By default, the NFS deals with this latter problem in a severe manner: +it does not allow root access across the network by +.I uid  +0 at all. +.LP +DES authentication corrects these problems +by basing naming upon new names that we call +.I netnames. +Simply put, a netname is just a string of printable characters, +and fundamentally, it is really these netnames that we authenticate. +The public and secret keys are stored on a per-netname, +rather than per-username, basis. +The Yellow Pages map +.I netid.byname +maps the netname into a local +.I uid  +and group-access-list,  +though non-Sun environments may map the netname into something else. +.LP +We solve the Internet naming problem by choosing globally unique netnames. +This is far easier then choosing globally unique user IDs. +In the Sun environment, user names are unique within each Yellow Page domain. +Netnames are assigned by concatenating the operating system and user ID +with the Yellow Pages and ARPA domain names. +For example, a UNIX system user with a user ID of 508 in the domain +.I eng.sun.COM  +would be assigned the following netname: +.I unix.508@eng.sun.COM . +A good convention for naming domains is to append  +the ARPA domain name (COM, EDU, GOV, MIL) to the local domain name. +Thus, the Yellow Pages domain +.I eng  +within the ARPA domain +.I sun.COM  +becomes +.I eng.sun.COM . +.LP +We solve the problem of multiple super-users per domain +by assigning netnames to machines as well as to users. +A machine's netname is formed much like a user's. +For example, a UNIX machine named +.I hal  +in the same domain as before has the netname +.I unix.hal@eng.sun.COM . +Proper authentication of machines is very important for diskless machines +that need full access to their home directories over the net. +.LP +Non-Sun environments will have other ways of generating netnames,  +but this does not preclude them from accessing +the secure network services of the Sun environment. +To authenticate users from any remote domain, +all that has to be done is make entries for them in two Yellow Pages databases. +One is an entry for their public and secret keys,  +the other is for their local +.I uid  +and group-access-list mapping. +Upon doing this, users in the remote domain +will be able access all of the local network services, +such as the NFS and remote logins. +.# +.NH 1 +\&Applications of DES Authentication +.IX "applications of DES authentication" +.IX "authentication" "DES" +.LP +The first application of DES authentication +is a generalized Yellow Pages update service.  +This service allows users to update private fields in Yellow Page databases. +So far the Yellow Pages maps +.I hosts, +.I ethers, +.I bootparams +and +.I publickey +employ the DES-based update service. +Before the advent of an update service for mail aliases, +Sun had to hire a full-time person just to update mail aliases. +.LP +The second application of DES authentication is the most important:  +a more secure Network File System. +There are three security problems with the  +old NFS using UNIX authentication. +The first is that verification of credentials occurs only at mount time +when the client gets from the server a piece of information +that is its key to all further requests: the +.I "file handle" . +Security can be broken if one can figure out a file handle +without contacting the server, perhaps by tapping into the net or by guessing. +After an NFS file system has been mounted, +there is no checking of credentials during file requests, +which brings up the second problem. +If a file system has been mounted from a server that serves multiple clients +(as is typically the case), there is no protection +against someone who has root permission on their machine using +.I su  +(or some other means of changing +.I uid ) +gaining unauthorized access to other people's files. +The third problem with the NFS is the severe method it uses to circumvent +the problem of not being able to authenticate remote client super-users:  +denying them super-user access altogether.  +.LP +The new authentication system corrects all of these problems.  +Guessing file handles is no longer a problem since in order to gain  +unauthorized access, the miscreant will also have to guess the right  +encrypted timestamp to place in the credential, +which is a virtually impossible task. +The problem of authenticating root users is solved, +since the new system can authenticate machines. +At this point, however, +secure NFS is not used for root filesystems. +Root users of nonsecure filesystems are identified by IP address. +.LP +Actually, the level of security associated with each filesystem +may be altered by the administrator.  The file +.I /etc/exports  +.IX "etc/exports" "" "\&\fI/etc/exports\fP" +contains a list of filesystems and which machines may mount them.  +By default, filesystems are exported with UNIX authentication, +but the administrator can have them exported with DES authentication +by specifying +.I -secure  +on any line in the +.I /etc/exports  +file.  Associated with DES authentication is a parameter: +the maximum window size that the server is willing to accept. +.# +.NH 1 +\&Security Issues Remaining +.IX "security" "issues remaining" +.IX "remaining security issues" +.LP +There are several ways to break DES authentication, but using +.I su  +is not one of them.  In order to be authenticated, +your secret key must be stored by your workstation. +This usually occurs when you login, with the +.I login  +program decrypting your secret key with your login password, +and storing it away for you. +If somebody tries to use +.I su  +to impersonate you, it won't work, +because they won't be able to decrypt your secret key.  Editing +.I /etc/passwd  +isn't going to help them either, because the thing they need to edit,  +your encrypted secret key, is stored in the Yellow Pages. +If you log into somebody else's workstation and type in your password, +then your secret key would be stored in their workstation and they could use +.I su  +to impersonate you.  But this is not a problem since you should not +be giving away your password to a machine you don't trust anyway.  +Someone on that machine could just as easily change +.I login  +to save all the passwords it sees into a file.  +.LP +Not having +.I su  +to employ any more, how can nefarious users impersonate others now? +Probably the easiest way is to guess somebody's password, +since most people don't choose very secure passwords. +We offer no protection against this; +it's up to each user to choose a secure password. +.LP +The next best attack would be to attempt replays. +For example, let's say I have been squirreling away +all of your NFS transactions with a particular server. +As long as the server remains up, +I won't succeed by replaying them since the server always demands timestamps +that are greater than the previous ones seen. +But suppose I go and pull the plug on your server, causing it to crash. +As it reboots, its credential table will be clean, +so it has lost all track of previously seen timestamps, +and now I am free to replay your transactions. +There are few things to be said about this. +First of all, servers should be kept in a secure place +so that no one can go and pull the plug on them. +But even if they are physically secure, +servers occasionally crash without any help. +Replaying transactions is not a very big security problem, +but even so, there is protection against it. +If a client specifies a window size that is smaller than the time it takes +a server to reboot (5 to 10 minutes), the server will reject +any replayed transactions because they will have expired. +.LP +There are other ways to break DES authentication,  +but they are much more difficult. +These methods involve breaking the DES key itself, +or computing the logarithm of the public key, +both of which would would take months of compute time on a supercomputer. +But it is important to keep our goals in mind. +Sun did not aim for super-secure network computing. +What we wanted was something as secure as a good time-sharing system, +and in that we have been successful. +.LP +There is another security issue that DES authentication does not address,  +and that is tapping of the net. +Even with DES authentication in place,  +there is no protection against somebody watching what goes across the net. +This is not a big problem for most things, +such as the NFS, since very few files are not publically readable, and besides, +trying to make sense of all the bits flying over the net is not a trivial task. +For logins, this is a bit of a problem because you wouldn't  +want somebody to pick up your password over the net. +As we mentioned before, +a side effect of the authentication system is a key exchange,  +so that the network tapping problem can be tackled on a per-application basis. +.# +.NH 1 +\&Performance +.IX "performance of DES authentication" +.IX "authentication" "performance" +.LP +Public key systems are known to be slow, +but there is not much actual public key encryption going on in Sun's system. +Public key encryption only occurs in the first transaction with a service, +and even then, there is caching that speeds things up considerably. +The first time a client program contacts a server, +both it and the server will have to calculate the common key. +The time it takes to compute the common key is basically the time it takes +to compute an exponential modulo $M$. +On a Sun-3 using a 192-bit modulus, this takes roughly 1 second,  +which means it takes 2 seconds just to get things started, +since both client and server have to perform this operation. +This is a long time, +but you have to wait only the first time you contact a machine. +Since the keyserver caches the results of previous computations,  +it does not have to recompute the exponential every time. +.LP +The most important service in terms of performance is the secure NFS, +which is acceptably fast. +The extra overhead that DES authentication requires versus UNIX authentication  +is the encryption. +A timestamp is a 64-bit quantity, +which also happens to be the DES block size. +Four encryption operations take place in an average RPC transaction: +the client encrypts the request timestamp, the server decrypts it, +the server encrypts the reply timestamp, and the client decrypts it. +On a Sun-3, the time it takes to encrypt one block is about +half a millisecond if performed by hardware, +and 1.2 milliseconds if performed by software. +So, the extra time added to the round trip time is about  +2 milliseconds for hardware encryption and 5 for software. +The round trip time for the average NFS request is about 20 milliseconds, +resulting in a performance hit of 10 percent if one has encryption hardware,  +and 25 percent if not. +Remember that this is the impact on network performance. +The fact is that not all file operations go over the wire, +so the impact on total system performance will actually be lower than this. +It is also important to remember that security is optional,  +so environments that require higher performance can turn it off. +.# +.NH 1 +\&Problems with Booting and \&\fBsetuid\fP Programs +.IX "problems with booting and \&\fIsetuid\fP programs" +.IX "booting and \&\fIsetuid\fP problems" +.LP +Consider the problem of a machine rebooting, +say after a power failure at some strange hour when nobody is around. +All of the secret keys that were stored get wiped out, +and now no process will be able to access secure network services, +such as mounting an NFS filesystem. +The important processes at this time are usually root processes, +so things would work OK if root's secret key were stored away,  +but nobody is around to type the password that decrypts it. +The solution to this problem is to store root's decrypted secret key in a file, +which the keyserver can read. +This works well for diskful machines that can store the secret key +on a physically secure local disk, +but not so well for diskless machines, +whose secret key must be stored across the network. +If you tap the net when a diskless machine is booting, +you will find the decrypted key. +This is not very easy to accomplish, though. +.LP +Another booting problem is the single-user boot. +There is a mode of booting known as single-user mode, where a +.I root  +login shell appears on the console. +The problem here is that a password is not required for this.  +With C2 security installed, +a password is required in order to boot single-user. +Without C2 security installed, +machines can still be booted single-user without a password, +as long as the entry for +.I console  +in the +.I /etc/ttytab  +.IX "etc/ttytab" "" "\&\fI/etc/ttytab\fP" +file is labeled as physically +.I secure  +(this is the default). +.LP +Yet another problem is that diskless machine booting is not totally secure. +It is possible for somebody to impersonate the boot-server, +and boot a devious kernel that, for example,  +makes a record of your secret key on a remote machine. +The problem is that our system is set up to provide protection +only after the kernel and the keyserver are running. +Before that, there is no way to authenticate +the replies given by the boot server. +We don't consider this a serious problem, +because it is highly unlikely that somebody would be able to write +this funny kernel without source code. +Also, the crime is not without evidence. +If you polled the net for boot-servers,  +you would discover the devious boot-server's location. +.LP +Not all +.I setuid  +programs will behave as they should. +For example, if a  +.I setuid  +program is owned by +.I dave , +who has not logged into the machine since it booted, +then the program will not be able to access any secure network services as +.I dave . +The good news is that most +.I setuid  +programs are owned by root,  +and since root's secret key is always stored at boot time,  +these programs will behave as they always have. +.# +.NH 1 +\&Conclusion +.IX "network security" "summary" +.LP +Our goal was to build a system as secure as a time-shared system.  +This goal has been met. +The way you are authenticated in a time-sharing system +is by knowing your password. +With DES authentication, the same is true. +In time-sharing the person you trust is your system administrator, +who has an ethical obligation +not to change your password in order to impersonate you. +In Sun's system, you trust your network administrator, +who does not alter your entry in the public key database. +In one sense, our system is even more secure than time-sharing, +because it is useless to place a tap on the network +in hopes of catching a password or encryption key,  +since these are encrypted. +Most time-sharing environments do not encrypt data emanating from the terminal; +users must trust that nobody is tapping their terminal lines. +.LP +DES authentication is perhaps not the ultimate authentication system.  +In the future it is likely there will be sufficient advances  +in algorithms and hardware to render the public key system +as we have defined it useless. +But at least DES authentication offers a smooth migration path for the future. +Syntactically speaking, +nothing in the protocol requires the encryption of the conversation  +key to be Diffie-Hellman, or even public key encryption in general.  +To make the authentication stronger in the future, +all that needs to be done is to strengthen the way +the conversation key is encrypted.  +Semantically, this will be a different protocol, +but the beauty of RPC is that it can be plugged in +and live peacefully with any authentication system. +.LP +For the present at least, DES authentication satisfies our requirements +for a secure networking environment. +From it we built a system secure enough for use in unfriendly networks, +such as a student-run university workstation environment. +The price for this security is not high. +Nobody has to carry around a magnetic card or remember +any hundred digit numbers. +You use your login password to authenticate yourself, just as before. +There is a small impact on performance, +but if this worries you and you have a friendly net, +you can turn authentication off. +.# +.NH 1 +\&References +.IX "references on network security" +.LP +Diffie and Hellman, ``New Directions in Cryptography,'' +\fIIEEE Transactions on Information Theory IT-22,\fP +November 1976. +.LP +Gusella & Zatti, ``TEMPO: A Network Time Controller +for a Distributed Berkeley UNIX System,'' +\fIUSENIX 1984 Summer Conference Proceedings,\fP +June 1984. +.LP +National Bureau of Standards, ``Data Encryption Standard,'' +\fIFederal Information Processing Standards Publication 46,\fP +January 15, 1977. +.LP +Needham & Schroeder, ``Using Encryption for Authentication +in Large Networks of Computers,'' +\fIXerox Corporation CSL-78-4,\fP +September 1978. +.EQ +delim off +.EN +.IX "security" "of networks" "" "" PAGE END +.IX "network security" "" "" "" PAGE END +.IX "NFS security" "" "" "" PAGE END diff --git a/lib/librpc/secure_rpc/keyserv/Makefile b/lib/librpc/secure_rpc/keyserv/Makefile new file mode 100644 index 000000000000..de6771ee0d58 --- /dev/null +++ b/lib/librpc/secure_rpc/keyserv/Makefile @@ -0,0 +1,49 @@ +# +# @(#)Makefile	2.4 88/08/15 4.0 RPCSRC; from 1.9 87/11/29 SMI +# +CFLAGS= -O +RPCLIB= -lrpclib +#RPCLIB= -lrpcsvc + +KEYSERV_OBJS = keyserv.o setkey.o detach.o mp.o +KEYENVOY_OBJS = keyenvoy.o +SRCS = keyserv.c setkey.c detach.c keyenvoy.c mp.c + +ALL= keyserv keyenvoy + +all: $(ALL) + +keyserv: $(KEYSERV_OBJS) +	$(CC) $(CFLAGS) $(KEYSERV_OBJS) -lmp $(LIBC) $(RPCLIB) -o $@ + +keyenvoy:	$(KEYENVOY_OBJS) +	$(CC) $(CFLAGS) $(KEYENVOY_OBJS) $(LIBC) $(RPCLIB) -o $@ + +clean: +	rm -f $(ALL) $(KEYSERV_OBJS) $(KEYENVOY_OBJS) + +install: $(ALL) +	install -s -m  755 keyserv  $(DESTDIR)/usr/etc +	install -s -m 4755 keyenvoy $(DESTDIR)/usr/etc + +depend: +	rm -f makedep +	for i in ${SRCS}; do \ +	    ${CC} -M ${INCPATH} $$i | \ +	    awk ' { if ($$1 != prev) { print rec; rec = $$0; prev = $$1; } \ +		else { if (length(rec $$2) > 78) { print rec; rec = $$0; } \ +		else rec = rec " " $$2 } } \ +		END { print rec } ' >> makedep; done +	echo '/^# DO NOT DELETE THIS LINE/+2,$$d' >eddep +	echo '$$r makedep' >>eddep +	echo 'w' >>eddep +	cp Makefile Makefile.bak +	ed - Makefile < eddep +	rm eddep makedep +	echo '# DEPENDENCIES MUST END AT END OF FILE' >> Makefile +	echo '# IF YOU PUT STUFF HERE IT WILL GO AWAY' >> Makefile +	echo '# see make depend above' >> Makefile + +# DO NOT DELETE THIS LINE -- make depend uses it + + diff --git a/lib/librpc/secure_rpc/keyserv/detach.c b/lib/librpc/secure_rpc/keyserv/detach.c new file mode 100644 index 000000000000..ff1fac3dac37 --- /dev/null +++ b/lib/librpc/secure_rpc/keyserv/detach.c @@ -0,0 +1,69 @@ +#ifndef lint +static char sccsid[] = 	"@(#)detach.c	2.2 88/08/10 4.0 RPCSRC"; +#endif +/* + * Sun RPC is a product of Sun Microsystems, Inc. and is provided for + * unrestricted use provided that this legend is included on all tape + * media and as a part of the software program in whole or part.  Users + * may copy or modify Sun RPC without charge, but are not authorized + * to license or distribute it to anyone else except as part of a product or + * program developed by the user. + *  + * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE + * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR + * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. + *  + * Sun RPC is provided with no support and without any obligation on the + * part of Sun Microsystems, Inc. to assist in its use, correction, + * modification or enhancement. + *  + * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE + * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC + * OR ANY PART THEREOF. + *  + * In no event will Sun Microsystems, Inc. be liable for any lost revenue + * or profits or other special, indirect and consequential damages, even if + * Sun has been advised of the possibility of such damages. + *  + * Sun Microsystems, Inc. + * 2550 Garcia Avenue + * Mountain View, California  94043 + */ + +/* + * Copyright (C) 1986, Sun Microsystems, Inc. + */ + +#include <sys/ioctl.h> +#include <fcntl.h> + +/* + * detach from tty + */ +detachfromtty() +{ +	int tt; + +	close(0); +	close(1); +	close(2); +	switch (fork()) { +	case -1: +		perror("fork"); +		break; +	case 0: +		break; +	default: +		exit(0); +	} +	tt = open("/dev/tty", O_RDWR); +	if (tt > 0) { +		ioctl(tt, TIOCNOTTY, 0); +		close(tt); +	} +	(void)open("/dev/null", O_RDWR, 0); +	dup(0); +	dup(0); +} +  + diff --git a/lib/librpc/secure_rpc/keyserv/keyenvoy.c b/lib/librpc/secure_rpc/keyserv/keyenvoy.c new file mode 100644 index 000000000000..5379651acb56 --- /dev/null +++ b/lib/librpc/secure_rpc/keyserv/keyenvoy.c @@ -0,0 +1,213 @@ +#ifndef lint +static char sccsid[] = 	"@(#)keyenvoy.c	2.2 88/08/10 4.0 RPCSRC"; +#endif +/* + * Sun RPC is a product of Sun Microsystems, Inc. and is provided for + * unrestricted use provided that this legend is included on all tape + * media and as a part of the software program in whole or part.  Users + * may copy or modify Sun RPC without charge, but are not authorized + * to license or distribute it to anyone else except as part of a product or + * program developed by the user. + *  + * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE + * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR + * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. + *  + * Sun RPC is provided with no support and without any obligation on the + * part of Sun Microsystems, Inc. to assist in its use, correction, + * modification or enhancement. + *  + * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE + * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC + * OR ANY PART THEREOF. + *  + * In no event will Sun Microsystems, Inc. be liable for any lost revenue + * or profits or other special, indirect and consequential damages, even if + * Sun has been advised of the possibility of such damages. + *  + * Sun Microsystems, Inc. + * 2550 Garcia Avenue + * Mountain View, California  94043 + */ + +/* + * Copyright (C) 1986, Sun Microsystems, Inc. + */ +#include <stdio.h> +#include <rpc/rpc.h> +#include <rpc/key_prot.h> +#include <sys/socket.h> +#include <sys/types.h> +#include <sys/time.h> +#include <fcntl.h> + +/* + * Talk to the keyserver on a privileged port on the part of a calling program. + * + * Protocol is for caller to send through stdin the procedure number  + * to call followed by the argument data.  We call the keyserver, and + * send the results back to the caller through stdout. + * Non-zero exit status means something went wrong. + */ + +#ifndef DEBUG +#define debug(msg)	 +#endif + +#define TOTAL_TIMEOUT 30	/* total timeout talking to keyserver */ +#define TOTAL_TRIES	  10	/* Number of tries */ + +/* + * Opaque data that we send and receive + */ +#define MAXOPAQUE 256 +struct opaqn { +	u_int len;	 +	u_int data[MAXOPAQUE]; +}; +bool_t xdr_opaqn(); + + +main(argc,argv) +	int argc; +	char *argv[]; +{ +	XDR xdrs_args; +	XDR xdrs_rslt; +	int proc; +	struct opaqn args, rslt; + + +	if (isatty(0)) { +		fprintf(stderr,  +			"This program cannot be used interactively.\n"); +		exit(1); +	} + +#ifdef DEBUG +	close(2); +	open("/dev/console", O_WRONLY, 0); +#endif + +	xdrstdio_create(&xdrs_args, stdin, XDR_DECODE); +	xdrstdio_create(&xdrs_rslt, stdout, XDR_ENCODE); + +	if ( ! xdr_u_long(&xdrs_args, &proc)) { +		debug("no proc"); +		exit(1); +	} +	if (! xdr_opaqn(&xdrs_args, &args)) { +		debug("recving args failed"); +		exit(1); +	}	 +	if (! callkeyserver(proc, xdr_opaqn, &args, xdr_opaqn, &rslt)) { +		debug("rpc_call failed"); +		exit(1); +	} +	if (! xdr_opaqn(&xdrs_rslt, &rslt)) { +		debug("sending args failed"); +		exit(1); +	} +	exit(0); +} + + + +callkeyserver(proc, xdr_args, args, xdr_rslt, rslt) +	u_long proc; +	bool_t (*xdr_args)(); +	void *args; +	bool_t (*xdr_rslt)(); +	void *rslt; + +{ +	struct sockaddr_in remote; +	int port; +	struct timeval wait; +	enum clnt_stat stat; +	CLIENT *client; +	int sd; + +	/* +  	 * set up the remote address +	 * and create client +	 */ +	remote.sin_addr.s_addr = htonl(INADDR_LOOPBACK); +	remote.sin_family = AF_INET; +	remote.sin_port = 0; +	wait.tv_sec = TOTAL_TIMEOUT/TOTAL_TRIES; wait.tv_usec = 0; +	sd = RPC_ANYSOCK; +	client = clntudp_create(&remote, KEY_PROG, KEY_VERS, wait, &sd); +	if (client == NULL) { +		debug("no client"); +		return (0); +	} + +	/* +	 * Check that server is bound to a reserved port, so +	 * that noone can masquerade as the keyserver. +	 */ +	if (ntohs(remote.sin_port) >= IPPORT_RESERVED) { +		debug("insecure port"); +		return (0); +	} + +	/* +	 * Create authentication +	 * All we care about really is sending the real uid +	 */ +	client->cl_auth = authunix_create("", getuid(), 0, 0, NULL); +	if (client->cl_auth == NULL) { +		debug("no auth"); +		return (0); +	} +	wait.tv_sec = TOTAL_TIMEOUT; wait.tv_usec = 0; +	stat = clnt_call(client, proc, xdr_args, args, xdr_rslt, rslt, wait);  +	if (stat != RPC_SUCCESS) { +		debug("clnt_call failed"); +	} +	return (stat == RPC_SUCCESS); +} + + +/* + * XDR opaque data + * Don't know the length on decode, so just keep receiving until failure. + */  +bool_t +xdr_opaqn(xdrs, objp) +	XDR *xdrs; +	struct opaqn *objp; +{ +	int i; + +	switch (xdrs->x_op) { +	case XDR_FREE: +		break;	 +	case XDR_DECODE: +		for (i = 0; i < MAXOPAQUE &&  xdr_int(xdrs, &objp->data[i]); i++) { +		} +		if (i == MAXOPAQUE) { +			return (FALSE); +		} +		objp->len = i; +		break;	 +	case XDR_ENCODE: +		for (i = 0; i < objp->len; i++) { +			if (! xdr_int(xdrs, &objp->data[i])) { +				return (FALSE); +			} +		} +		break; +	} +	return (TRUE); +} + + +#ifdef DEBUG +debug(msg) +     char *msg; +{ +  fprintf(stderr, "%s\n", msg); +} +#endif diff --git a/lib/librpc/secure_rpc/keyserv/keyserv.c b/lib/librpc/secure_rpc/keyserv/keyserv.c new file mode 100644 index 000000000000..d82dc12a0f1e --- /dev/null +++ b/lib/librpc/secure_rpc/keyserv/keyserv.c @@ -0,0 +1,458 @@ +#ifndef lint +static char sccsid[] = 	"@(#)keyserv.c	2.4 88/08/15 4.0 RPCSRC Copyr 1988 Sun Micro"; +#endif +/* + * Sun RPC is a product of Sun Microsystems, Inc. and is provided for + * unrestricted use provided that this legend is included on all tape + * media and as a part of the software program in whole or part.  Users + * may copy or modify Sun RPC without charge, but are not authorized + * to license or distribute it to anyone else except as part of a product or + * program developed by the user. + *  + * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE + * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR + * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. + *  + * Sun RPC is provided with no support and without any obligation on the + * part of Sun Microsystems, Inc. to assist in its use, correction, + * modification or enhancement. + *  + * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE + * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC + * OR ANY PART THEREOF. + *  + * In no event will Sun Microsystems, Inc. be liable for any lost revenue + * or profits or other special, indirect and consequential damages, even if + * Sun has been advised of the possibility of such damages. + *  + * Sun Microsystems, Inc. + * 2550 Garcia Avenue + * Mountain View, California  94043 + */ + +/* + * Copyright (C) 1986, Sun Microsystems, Inc. + */ + +/* + * Keyserver  + * Store secret keys per uid. Do public key encryption and decryption + * operations. Generate "random" keys. Do not talk to anything but a local root + * process (by checking that the source port < IPPORT_RESERVED and by binding + * to the loopback address).  + */ + +#include <stdio.h> +#include <sys/param.h> +#include <rpc/rpc.h> +#include <sys/file.h> +#include <sys/socket.h> +#include <pwd.h> +#include <des_crypt.h> +#include <rpc/key_prot.h> + + +char ROOTKEY[] = "/etc/.rootkey"; + +extern long random(); + +extern keystatus pk_setkey(); +extern keystatus pk_encrypt(); +extern keystatus pk_decrypt(); + + +#ifdef DEBUG +int debugging = 1; +#else +int debugging = 0; +#endif + +static void keyprogram(); +des_block masterkey; + +main(argc, argv) +	int argc; +	char *argv[]; + +{ +	SVCXPRT *transp; +	int nflag; + +	nflag = (argc == 2) && (strcmp(argv[1], "-n") == 0); +	if (!(argc == 1 || nflag)) { +		(void) fprintf(stderr, "usage: %s [-n]\n", argv[0]); +		exit(1); +	} +	/* +	 * Initialize  +	 */ +	(void) umask(066);	/* paranoia */ +	if (geteuid() != 0) { +		(void) fprintf(stderr, "%s must be run as root\n", argv[0]); +		exit(1); +	} +	setmodulus(HEXMODULUS); +	openstore(); +	getrootkey(&masterkey, nflag); +	readkeys(); + +	/* +	 * create the service, register it, and run  +	 */ +	transp = svcudp_create(RPC_ANYSOCK); +	if (transp == NULL) { +		(void) fprintf(stderr, +			       "%s: unable to create udp service\n", argv[0]); +		exit(1); +	} +	pmap_unset(KEY_PROG, KEY_VERS); +	if (!svc_register(transp, KEY_PROG, KEY_VERS, keyprogram, +			  IPPROTO_UDP)) { +		(void) fprintf(stderr, "%s: unable to register service\n", +			       argv[0]); +		exit(1); +	} +	/* +	 * run  +	 */ +	if (!debugging) { +		detachfromtty(); +	} +	svc_run(); +	abort(); +} + +/* + * In the event that we don't get a root password, we try to randomize the + * master key the best we can  + */ +randomize(master) +	des_block *master; +{ +	int i; +	int seed; +	struct timeval tv; +	int shift; + +	seed = 0; +	for (i = 0; i < 1024; i++) { +		(void) gettimeofday(&tv, (struct timezone *) NULL); +		shift = i % 8 * sizeof(int); +		seed ^= (tv.tv_usec << shift) | (tv.tv_usec >> (32 - shift)); +	} +	srandom(seed); +	master->key.low = random(); +	master->key.high = random(); +	srandom(seed); +} + + + +/* + * Try to get root's secret key, by prompting if terminal is a tty, else trying + * from standard input.  + */ +getrootkey(master, prompt) +	des_block *master; +	int prompt; +{ +	char *getpass(); +	char *passwd; +	char name[MAXNETNAMELEN + 1]; +	char secret[HEXKEYBYTES + 1]; +	char *crypt(); +	int fd; + +	if (!prompt) { +		/* +		 * Read secret key out of $ROOTKEY  +		 */ +		fd = open(ROOTKEY, O_RDONLY, 0); +		if (fd < 0) { +			randomize(master); +			return (0); +		} +		if (read(fd, secret, HEXKEYBYTES) < 0) { +			(void) fprintf(stderr, "Invalid %s\n", ROOTKEY); +			(void) close(fd); +			return (0); +		} +		(void) close(fd); +		secret[HEXKEYBYTES] = 0; +	} else { +		/* +		 * Decrypt yellow pages entry to get secret key  +		 */ +		passwd = getpass("root password:"); +		passwd2des(passwd, master); +		getnetname(name); +		if (!getsecretkey(name, secret, passwd)) { +			(void) fprintf(stderr, +				       "Can't find %s's secret key\n", name); +			return (0); +		} +		if (secret[0] == 0) { +			(void) fprintf(stderr, +				       "Invalid password for %s\n", name); +			return (0); +		} +	} +	(void) pk_setkey(0, secret); +	return (1); +} + + +/* + * Procedures to implement RPC service + */ + +char * +strstatus(status) +	keystatus status; +{ +	switch (status) { +	case KEY_SUCCESS: +		return ("KEY_SUCCESS"); +	case KEY_NOSECRET: +		return ("KEY_NOSECRET"); +	case KEY_UNKNOWN: +		return ("KEY_UNKNOWN"); +	case KEY_SYSTEMERR: +		return ("KEY_SYSTEMERR"); +	default: +		return ("(bad result code)"); +	} +} + +keystatus * +key_set_1(uid, key) +	short uid; +	keybuf key; +{ +	static keystatus status; + +	if (debugging) { +		(void) fprintf(stderr, "set(%d, %.*s) = ", uid, +			       sizeof(keybuf), key); +	} +	status = pk_setkey(uid, key); +	if (debugging) { +		(void) fprintf(stderr, "%s\n", strstatus(status)); +		(void) fflush(stderr); +	} +	return (&status); +} + + + +cryptkeyres * +key_encrypt_1(uid, arg) +	short uid; +	cryptkeyarg *arg; +{ +	static cryptkeyres res; + +	if (debugging) { +		(void) fprintf(stderr, "encrypt(%d, %s, %08x%08x) = ", uid, +			       arg->remotename, arg->deskey.key.high, +			       arg->deskey.key.low); +	} +	res.cryptkeyres_u.deskey = arg->deskey; +	res.status = pk_encrypt(uid, arg->remotename, &res.cryptkeyres_u.deskey); +	if (debugging) { +		if (res.status == KEY_SUCCESS) { +			(void) fprintf(stderr, "%08x%08x\n", +				       res.cryptkeyres_u.deskey.key.high, +				       res.cryptkeyres_u.deskey.key.low); +		} else { +			(void) fprintf(stderr, +				       "%s\n", strstatus(res.status)); +		} +		(void) fflush(stderr); +	} +	return (&res); +} + +cryptkeyres * +key_decrypt_1(uid, arg) +	short uid; +	cryptkeyarg *arg; +{ +	static cryptkeyres res; + +	if (debugging) { +		(void) fprintf(stderr, "decrypt(%d, %s, %08x%08x) = ", uid, +			       arg->remotename, arg->deskey.key.high, +			       arg->deskey.key.low); +	} +	res.cryptkeyres_u.deskey = arg->deskey; +	res.status = pk_decrypt(uid, arg->remotename, +				&res.cryptkeyres_u.deskey); +	if (debugging) { +		if (res.status == KEY_SUCCESS) { +			(void) fprintf(stderr, "%08x%08x\n", +				       res.cryptkeyres_u.deskey.key.high, +				       res.cryptkeyres_u.deskey.key.low); +		} else { +			(void) fprintf(stderr, "%s\n", strstatus(res.status)); +		} +		(void) fflush(stderr); +	} +	return (&res); +} + +des_block * +key_gen_1() +{ +	struct timeval time; +	static des_block keygen; +	static des_block key; + +	(void) gettimeofday(&time, (struct timezone *) NULL); +	keygen.key.high += (time.tv_sec ^ time.tv_usec); +	keygen.key.low += (time.tv_sec ^ time.tv_usec); +	ecb_crypt(&masterkey, &keygen, sizeof(keygen), DES_ENCRYPT | DES_HW); +	key = keygen; +	des_setparity(&key); +	if (debugging) { +		(void) fprintf(stderr, "gen() = %08x%08x\n", key.key.high, +			       key.key.low); +		(void) fflush(stderr); +	} +	return (&key); +} + +/* ARGSUSED */ +getcredres * +key_getcred_1(uid, name) +	short uid; +	netnamestr *name; +{ +	static getcredres res; +	static int gids[NGROUPS]; +	struct unixcred *cred; + +	cred = &res.getcredres_u.cred; +	cred->gids.gids_val = gids; +	if (!netname2user(*name, &cred->uid, &cred->gid, +			  &cred->gids.gids_len, gids)) { +		res.status = KEY_UNKNOWN; +	} else { +		res.status = KEY_SUCCESS; +	} +	if (debugging) { +		(void) fprintf(stderr, "getcred(%s) = ", *name); +		if (res.status == KEY_SUCCESS) { +			(void) fprintf(stderr, "uid=%d,gid=%d,grouplen=%d\n", +				   cred->uid, cred->gid, cred->gids.gids_len); +		} else { +			(void) fprintf(stderr, "%s\n", strstatus(res.status)); +		} +		(void) fflush(stderr); +	} +	return (&res); +} + + +/* + * RPC boilerplate  + */ +static void +keyprogram(rqstp, transp) +	struct svc_req *rqstp; +	SVCXPRT *transp; +{ +	union { +		keybuf key_set_1_arg; +		cryptkeyarg key_encrypt_1_arg; +		cryptkeyarg key_decrypt_1_arg; +		des_block key_gen_1_arg; +	} argument; +	char *result; + +	bool_t(*xdr_argument) (), (*xdr_result) (); +	char *(*local) (); +	struct sockaddr_in remote; +	int uid; +	int check_auth; + +	switch (rqstp->rq_proc) { +	case NULLPROC: +		svc_sendreply(transp, xdr_void, (char *) NULL); +		return; + +	case KEY_SET: +		xdr_argument = xdr_keybuf; +		xdr_result = xdr_int; +		local = (char *(*)()) key_set_1; +		check_auth = 1; +		break; + +	case KEY_ENCRYPT: +		xdr_argument = xdr_cryptkeyarg; +		xdr_result = xdr_cryptkeyres; +		local = (char *(*)()) key_encrypt_1; +		check_auth = 1; +		break; + +	case KEY_DECRYPT: +		xdr_argument = xdr_cryptkeyarg; +		xdr_result = xdr_cryptkeyres; +		local = (char *(*)()) key_decrypt_1; +		check_auth = 1; +		break; + +	case KEY_GEN: +		xdr_argument = xdr_void; +		xdr_result = xdr_des_block; +		local = (char *(*)()) key_gen_1; +		check_auth = 0; +		break; + +	case KEY_GETCRED: +		xdr_argument = xdr_netnamestr; +		xdr_result = xdr_getcredres; +		local = (char *(*)()) key_getcred_1; +		check_auth = 0; +		break; + +	default: +		svcerr_noproc(transp); +		return; +	} +	if (check_auth) { +		remote = *svc_getcaller(transp); +		if (ntohs(remote.sin_port) >= IPPORT_RESERVED || +		    ntohl(remote.sin_addr.s_addr) != INADDR_LOOPBACK) { +			if (debugging) { +				(void) fprintf(stderr, +					      "not local privileged process\n"); +			} +			svcerr_weakauth(transp); +			return; +		} +		if (rqstp->rq_cred.oa_flavor != AUTH_UNIX) { +			if (debugging) { +				(void) fprintf(stderr, +					       "not unix authentication\n"); +			} +			svcerr_weakauth(transp); +			return; +		} +		uid = ((struct authunix_parms *) rqstp->rq_clntcred)->aup_uid; +	} +	bzero((char *) &argument, sizeof(argument)); +	if (!svc_getargs(transp, xdr_argument, &argument)) { +		svcerr_decode(transp); +		return; +	} +	result = (*local) (uid, &argument); +	if (!svc_sendreply(transp, xdr_result, (char *) result)) { +		(void) fprintf(stderr, "unable to reply\n"); +		svcerr_systemerr(transp); +	} +	if (!svc_freeargs(transp, xdr_argument, &argument)) { +		(void) fprintf(stderr, "unable to free arguments\n"); +		exit(1); +	} +} diff --git a/lib/librpc/secure_rpc/keyserv/mp.c b/lib/librpc/secure_rpc/keyserv/mp.c new file mode 100644 index 000000000000..97c85b06fecc --- /dev/null +++ b/lib/librpc/secure_rpc/keyserv/mp.c @@ -0,0 +1,145 @@ +#ifndef lint +static char sccsid[] = 	"@(#)mp.c	2.1 88/08/15 4.0 RPCSRC Copyr 1988 Sun Micro"; +#endif +/* + * Sun RPC is a product of Sun Microsystems, Inc. and is provided for + * unrestricted use provided that this legend is included on all tape + * media and as a part of the software program in whole or part.  Users + * may copy or modify Sun RPC without charge, but are not authorized + * to license or distribute it to anyone else except as part of a product or + * program developed by the user. + *  + * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE + * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR + * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. + *  + * Sun RPC is provided with no support and without any obligation on the + * part of Sun Microsystems, Inc. to assist in its use, correction, + * modification or enhancement. + *  + * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE + * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC + * OR ANY PART THEREOF. + *  + * In no event will Sun Microsystems, Inc. be liable for any lost revenue + * or profits or other special, indirect and consequential damages, even if + * Sun has been advised of the possibility of such damages. + *  + * Sun Microsystems, Inc. + * 2550 Garcia Avenue + * Mountain View, California  94043 + */ + +/* + * These routines add hexadecimal functionality to the multiple-precision + * library. + */ +#include <stdio.h> +#include <mp.h> + +void mfree(); + +/* + * Convert hex digit to binary value + */ +static int +xtoi(c) +	char c; +{ +	if (c >= '0' && c <= '9') { +		return(c - '0'); +	} else if (c >= 'a' && c <= 'f') { +		return(c - 'a' + 10); +	} else { +		return(-1); +	} +} + +/* + * Convert hex key to MINT key + */ +MINT * +xtom(key) +	char *key; +{ +	int digit; +	MINT *m = itom(0); +	MINT *d; +	MINT *sixteen; + 	sixteen = itom(16); +	for (; *key; key++) { +		digit = xtoi(*key); +		if (digit < 0) { +			return(NULL); +		} +		d = itom(digit); +		mult(m,sixteen,m); +		madd(m,d,m); +		mfree(d); +	} +	mfree(sixteen); +	return(m); +} +static char +itox(d) +	short d; +{ +	d &= 15; +	if (d < 10) { +		return('0' + d); +	} else { +		return('a' - 10 + d); +	} +} +/* + * Convert MINT key to hex key + */ +char * +mtox(key) +	MINT *key; +{ +	MINT *m = itom(0); +	MINT *zero = itom(0); +	short r; +	char *p; +	char c; +	char *s; +	char *hex; +	int size; +#define BASEBITS	(8*sizeof(short) - 1) + 	if (key->len >= 0) { +		size = key->len; +	} else { +		size = -key->len; +	} +	hex = malloc((unsigned) ((size * BASEBITS + 3)) / 4 + 1); +	if (hex == NULL) { +		return(NULL); +	} +	move(key,m); +	p = hex; +	do { +		sdiv(m,16,m,&r); +		*p++ = itox(r); +	} while (mcmp(m,zero) != 0); +	mfree(m); +	mfree(zero); + 	*p = 0; +	for (p--, s = hex; s < p; s++, p--) { +		c = *p; +		*p = *s; +		*s = c; +	} +	return(hex); +} +/* + * Deallocate a multiple precision integer + */ +void +mfree(a) +	MINT *a; +{ +	xfree(a); +	free((char *)a); +} + diff --git a/lib/librpc/secure_rpc/keyserv/setkey.c b/lib/librpc/secure_rpc/keyserv/setkey.c new file mode 100644 index 000000000000..d62dc9c7cf5c --- /dev/null +++ b/lib/librpc/secure_rpc/keyserv/setkey.c @@ -0,0 +1,514 @@ +#ifndef lint +static char sccsid[] = 	"@(#)setkey.c	2.2 88/08/10 4.0 RPCSRC; from Copyr 1988 Sun Micro"; +#endif +/* + * Sun RPC is a product of Sun Microsystems, Inc. and is provided for + * unrestricted use provided that this legend is included on all tape + * media and as a part of the software program in whole or part.  Users + * may copy or modify Sun RPC without charge, but are not authorized + * to license or distribute it to anyone else except as part of a product or + * program developed by the user. + *  + * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE + * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR + * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. + *  + * Sun RPC is provided with no support and without any obligation on the + * part of Sun Microsystems, Inc. to assist in its use, correction, + * modification or enhancement. + *  + * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE + * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC + * OR ANY PART THEREOF. + *  + * In no event will Sun Microsystems, Inc. be liable for any lost revenue + * or profits or other special, indirect and consequential damages, even if + * Sun has been advised of the possibility of such damages. + *  + * Sun Microsystems, Inc. + * 2550 Garcia Avenue + * Mountain View, California  94043 + */ + +/* + * Copyright (C) 1986, Sun Microsystems, Inc.  + */ + +/* + * Do the real work of the keyserver . + * Store secret keys. Compute common keys, + * and use them to decrypt and encrypt DES keys . + * Cache the common keys, so the + * expensive computation is avoided.  + */ +#include <stdio.h> +#include <sys/file.h> +#include <mp.h> +#include <rpc/rpc.h> +#include <rpc/key_prot.h> +#include <des_crypt.h> +#include <sys/errno.h> + +extern char *malloc(); +extern char ROOTKEY[]; + +static MINT *MODULUS; +static char *fetchsecretkey(); +static keystatus pk_crypt(); + + +/* + * Set the modulus for all our Diffie-Hellman operations  + */ +setmodulus(modx) +	char *modx; +{ +	MODULUS = xtom(modx); +} + + +/* + * Set the secretkey key for this uid  + */ +keystatus +pk_setkey(uid, skey) +	short uid; +	keybuf skey; +{ +	if (!storesecretkey(uid, skey)) { +		return (KEY_SYSTEMERR); +	} +	return (KEY_SUCCESS); +} + + +/* + * Encrypt the key using the public key associated with remote_name and the + * secret key associated with uid.  + */ +keystatus +pk_encrypt(uid, remote_name, key) +	short uid; +	char *remote_name; +	des_block *key; +{ +	return (pk_crypt(uid, remote_name, key, DES_ENCRYPT)); +} + + +/* + * Decrypt the key using the public key associated with remote_name and the + * secret key associated with uid.  + */ +keystatus +pk_decrypt(uid, remote_name, key) +	short uid; +	char *remote_name; +	des_block *key; +{ +	return (pk_crypt(uid, remote_name, key, DES_DECRYPT)); +} + + +/* + * Do the work of pk_encrypt && pk_decrypt  + */ +static keystatus +pk_crypt(uid, remote_name, key, mode) +	short uid; +	char *remote_name; +	des_block *key; +	int mode; +{ +	char *xsecret; +	char xpublic[HEXKEYBYTES + 1]; +	char xsecret_hold[HEXKEYBYTES + 1]; +	des_block deskey; +	int err; +	MINT *public; +	MINT *secret; +	MINT *common; +	char zero[8]; + +	xsecret = fetchsecretkey(uid); +	if (xsecret == NULL) { +		bzero(zero, sizeof(zero)); +		xsecret = xsecret_hold; +		if (!getsecretkey("nobody", xsecret, zero) || +		    xsecret[0] == 0) { +			return (KEY_NOSECRET); +		} +	} +	if (!getpublickey(remote_name, xpublic) && +	    !getpublickey("nobody", xpublic)) { +		return (KEY_UNKNOWN); +	} +	if (!readcache(xpublic, xsecret, &deskey)) { +		public = xtom(xpublic); +		secret = xtom(xsecret); +		common = itom(0); +		pow(public, secret, MODULUS, common); +		extractdeskey(common, &deskey); +		writecache(xpublic, xsecret, &deskey); +		mfree(secret); +		mfree(public); +		mfree(common); +	} +	err = ecb_crypt(&deskey, key, sizeof(des_block), DES_HW | mode); +	if (DES_FAILED(err)) { +		return (KEY_SYSTEMERR); +	} +	return (KEY_SUCCESS); +} + + +/* + * Choose middle 64 bits of the common key to use as our des key, possibly + * overwriting the lower order bits by setting parity.  + */ +static +extractdeskey(ck, deskey) +	MINT *ck; +	des_block *deskey; +{ +	MINT *a; +	short r; +	int i; +	short base = (1 << 8); +	char *k; + + +	a = itom(0); +	move(ck, a); +	for (i = 0; i < ((KEYSIZE - 64) / 2) / 8; i++) { +		sdiv(a, base, a, &r); +	} +	k = deskey->c; +	for (i = 0; i < 8; i++) { +		sdiv(a, base, a, &r); +		*k++ = r; +	} +	mfree(a); +	des_setparity(deskey); +} + + +/* + * Key storage management + */ + +struct secretkey_list { +	short uid; +	char secretkey[HEXKEYBYTES+1]; +	struct secretkey_list *next; +}; + +static struct secretkey_list *g_secretkeys; + +/* + * Fetch the secret key for this uid  + */ +static char * +fetchsecretkey(uid) +	short uid; +{ +	struct secretkey_list *l; + +	for (l = g_secretkeys; l != NULL; l = l->next) { +		if (l->uid == uid) { +			return (l->secretkey); +		} +	} +	return (NULL); +} + +/* + * Store the secretkey for this uid  + */ +storesecretkey(uid, key) +	short uid; +	keybuf key; +{ +	struct secretkey_list *new; +	struct secretkey_list **l; +	int nitems; + + +	nitems = 0; +	for (l = &g_secretkeys; *l != NULL && (*l)->uid != uid;  +	     l = &(*l)->next) { +		nitems++; +	} +	if (*l == NULL) { +		new = (struct secretkey_list *)malloc(sizeof(*new)); +		if (new == NULL) { +			return (0); +		} +		new->uid = uid; +		new->next = NULL; +		*l = new; +	} else { +		new = *l; +	} +	bcopy(key, new->secretkey, HEXKEYBYTES); +	new->secretkey[HEXKEYBYTES] = 0; +	seekitem(nitems); +	writeitem(uid, new->secretkey); +	return (1); +} + + +hexdigit(val) +	int val; +{ +	return ("0123456789abcdef"[val]); + +} +bin2hex(bin, hex, size) +	unsigned char *bin; +	unsigned char *hex; +	int size; +{ +	int i; + +	for (i = 0; i < size; i++) { +		*hex++ = hexdigit(*bin >> 4); +		*hex++ = hexdigit(*bin++ & 0xf); +	} +} + +hexval(dig) +	char dig; +{ +	if ('0' <= dig && dig <= '9') { +		return (dig - '0'); +	} else if ('a' <= dig && dig <= 'f') { +		return (dig - 'a' + 10); +	} else if ('A' <= dig && dig <= 'F') { +		return (dig - 'A' + 10); +	} else { +		return (-1); +	} +} + +hex2bin(hex, bin, size) +	unsigned char *hex; +	unsigned char *bin; +	int size; +{ +	int i; + +	for (i = 0; i < size; i++) { +		*bin = hexval(*hex++) << 4; +		*bin++ |= hexval(*hex++); +	} +} + +static char KEYSTORE[] = "/etc/keystore"; +FILE *kf; + +openstore() +{ +	kf = fopen(KEYSTORE, "r+"); +	if (kf == NULL) { +		kf = fopen(KEYSTORE, "w+"); +		if (kf == NULL) { +			return (0); +		} +	} +	setbuf(kf, NULL); +	return (1); +} + +static char rootkey[KEYBYTES]; +static int haverootkey; +struct storedkey { +	short uid; +	char crypt[KEYBYTES]; +}; + +readkeys() +{ +	struct secretkey_list *node; +	struct secretkey_list **l; +	int uid; +	char secretkey[HEXKEYBYTES+1]; + +	if (kf == NULL) { +		return; +	} +	l = &g_secretkeys; +	seekitem(0); +	while (readitem(&uid, secretkey)) { +		node = (struct secretkey_list *)malloc(sizeof(*node)); +		if (node == NULL) { +			return; +		} +		node->uid = uid; +		bcopy(secretkey, node->secretkey, HEXKEYBYTES + 1); +		node->next = NULL; +		*l = node; +		l = &node->next; +	} +} + +writekeys() +{ +	struct secretkey_list *k; + +	seekitem(0); +	for (k = g_secretkeys; k != NULL; k = k->next) { +		writeitem(k->uid, k->secretkey); +	} +} + +seekitem(item) +	int item; +{ +	if (kf != NULL) { +		fseek(kf, item * sizeof(struct storedkey), 0); +	} +} + +writeitem(uid, key) +	int uid; +	char *key; +{ +	struct storedkey item; +	char rootkey_tmp[KEYBYTES]; +	int reencrypt; +	 +	if (kf == NULL) { +		return (1); +	} +	if (uid == 0) { +		writerootkey(key); +		hex2bin(key, rootkey_tmp, KEYBYTES); +		reencrypt = (haverootkey && +			     bcmp(rootkey, rootkey_tmp, KEYBYTES) != 0); +		bcopy(rootkey_tmp, rootkey, KEYBYTES); +		haverootkey = 1; +		if (reencrypt) { +			writekeys(); +			return (1); +		} +	} +	if (!haverootkey) { +		return (1); +	} +	item.uid = uid; +	hex2bin(key, item.crypt, KEYBYTES); +	ecb_crypt(rootkey, item.crypt, KEYBYTES, DES_ENCRYPT|DES_HW); +	return (fwrite(&item, sizeof(item), 1, kf) >= 0); +} + + +readitem(uidp, key) +	int *uidp; +	char *key; +{ +	struct storedkey item; + +	if (!haverootkey || kf == NULL) { +		return (0); +	} +	if (fread(&item, sizeof(item), 1, kf) != 1) { +		return (0); +	} +	*uidp = item.uid; +	ecb_crypt(rootkey, item.crypt, KEYBYTES, DES_DECRYPT|DES_HW); +	bin2hex(item.crypt, key, KEYBYTES); +	key[HEXKEYBYTES] = 0; +	return (1); +} +	 +/* + * Root users store their key in /etc/$ROOTKEY so + * that they can auto reboot without having to be + * around to type a password. Storing this in a file + * is rather dubious: it should really be in the EEPROM + * so it does not go over the net for diskless machines. + */ +writerootkey(secret) +	char *secret; +{ +	char newline = '\n'; +	int fd; + +	fd = open(ROOTKEY, O_WRONLY|O_TRUNC|O_CREAT, 0); +	if (fd < 0) { +		perror(ROOTKEY); +	} else { +		if (write(fd, secret, strlen(secret)) < 0 || +		    write(fd, &newline, sizeof(newline)) < 0) { +			(void)fprintf(stderr, "%s: ", ROOTKEY); +			perror("write"); +		} +		close(fd); +	} +} + + +/* + * Exponential caching management + */ +struct cachekey_list { +	keybuf secret; +	keybuf public; +	des_block deskey; +	struct cachekey_list *next; +}; +static struct cachekey_list *g_cachedkeys; + + +/* + * cache result of expensive multiple precision exponential operation  + */ +static +writecache(pub, sec, deskey) +	char *pub; +	char *sec; +	des_block *deskey; +{ +	struct cachekey_list *new; + +	new = (struct cachekey_list *) malloc(sizeof(struct cachekey_list)); +	if (new == NULL) { +		return; +	} +	bcopy(pub, new->public, sizeof(keybuf)); +	bcopy(sec, new->secret, sizeof(keybuf)); +	new->deskey = *deskey; +	new->next = g_cachedkeys; +	g_cachedkeys = new; +} + +/* + * Try to find the common key in the cache  + */ +static +readcache(pub, sec, deskey) +	char *pub; +	char *sec; +	des_block *deskey; +{ +	struct cachekey_list *found; +	register struct cachekey_list **l; + +#define cachehit(pub, sec, list)	\ +		(bcmp(pub, (list)->public, sizeof(keybuf)) == 0 && \ +		bcmp(sec, (list)->secret, sizeof(keybuf)) == 0) + +	for (l = &g_cachedkeys; +	     (*l) != NULL && !cachehit(pub, sec, *l); +	     l = &(*l)->next); +	if ((*l) == NULL) { +		return (0); +	} +	found = *l; +	(*l) = (*l)->next; +	found->next = g_cachedkeys; +	g_cachedkeys = found; +	*deskey = found->deskey; +	return (1); +} diff --git a/lib/librpc/secure_rpc/man/chkey.1 b/lib/librpc/secure_rpc/man/chkey.1 new file mode 100644 index 000000000000..fbf1fcd74c34 --- /dev/null +++ b/lib/librpc/secure_rpc/man/chkey.1 @@ -0,0 +1,19 @@ +.\"  @(#)chkey.1	2.1 88/08/10 4.0 RPCSRC; from 1.6 88/02/29 SMI; +.TH CHKEY 1 "9 September 1987" +.SH NAME +chkey \- change your encryption key +.SH SYNOPSIS +.B chkey +.SH DESCRIPTION +.IX  "chkey command"  ""  "\fLchkey\fP command" +.IX  "encryption key, change, \fLchkey\fR command" +.B chkey +prompts the user for their login password, and uses it to encrypt +a new encryption key for the user to be stored in the +.BR publickey (5) +database. +.SH "SEE ALSO" +.BR keylogin (1), +.BR publickey (5), +.BR keyserv (8C), +.BR newkey (8) diff --git a/lib/librpc/secure_rpc/man/des_crypt.3 b/lib/librpc/secure_rpc/man/des_crypt.3 new file mode 100644 index 000000000000..ca0a33e1c27d --- /dev/null +++ b/lib/librpc/secure_rpc/man/des_crypt.3 @@ -0,0 +1,126 @@ +.\" @(#)des_crypt.3	2.1 88/08/11 4.0 RPCSRC; from 1.16 88/03/02 SMI; +.TH DES_CRYPT 3  "6 October 1987" +.SH NAME +des_crypt, ecb_crypt, cbc_crypt, des_setparity \- fast DES encryption +.SH SYNOPSIS +.nf +.B #include <des_crypt.h> +.LP +.B int ecb_crypt(key, data, datalen, mode) +.B char *key; +.B char *data; +.B unsigned datalen; +.B unsigned mode; +.LP +.B int cbc_crypt(key, data, datalen, mode, ivec) +.B char *key; +.B char *data; +.B unsigned datalen; +.B unsigned mode; +.B char *ivec; +.LP +.B void des_setparity(key) +.B char *key; +.fi +.SH DESCRIPTION +.IX encryption cbc_crypt "" \fLcbc_crypt\fP +.IX "des encryption" cbc_crypt "DES encryption" \fLcbc_crypt\fP +.IX encryption des_setparity "" \fLdes_setparity\fP +.IX "des encryption" des_setparity "DES encryption" \fLdes_setparity\fP +.B ecb_crypt(\|) +and +.B cbc_crypt(\|) +implement the +.SM NBS +.SM DES +(Data Encryption Standard). +These routines are faster and more general purpose than +.BR crypt (3). +They also are able to utilize +.SM DES +hardware if it is available. +.B ecb_crypt(\|) +encrypts in +.SM ECB +(Electronic Code Book) +mode, which encrypts blocks of data independently. +.B cbc_crypt(\|) +encrypts in +.SM CBC +(Cipher Block Chaining) +mode, which chains together +successive blocks. +.SM CBC +mode protects against insertions, deletions and +substitutions of blocks. Also, regularities in the clear text will +not appear in the cipher text. +.LP +Here is how to use these routines.  The first parameter, +.IR key , +is the 8-byte encryption key with parity. +To set the key's parity, which for +.SM DES +is in the low bit of each byte, use +.IR des_setparity . +The second parameter, +.IR data , +contains the data to be encrypted or decrypted. The +third parameter, +.IR datalen , +is the length in bytes of +.IR data , +which must be a multiple of 8. The fourth parameter, +.IR mode , +is formed by +.SM OR\s0'ing +together some things.  For the encryption direction 'or' in either +.SM DES_ENCRYPT +or +.SM DES_DECRYPT\s0. +For software versus hardware +encryption, 'or' in either +.SM DES_HW +or +.SM DES_SW\s0. +If +.SM DES_HW +is specified, and there is no hardware, then the encryption is performed +in software and the routine returns +.SM DESERR_NOHWDEVICE\s0. +For +.IR cbc_crypt , +the parameter +.I ivec +is the the 8-byte initialization +vector for the chaining.  It is updated to the next initialization +vector upon return. +.LP +.SH "SEE ALSO" +.BR des (1), +.BR crypt (3) +.SH DIAGNOSTICS +.PD 0 +.TP 20 +.SM DESERR_NONE +No error. +.TP +.SM DESERR_NOHWDEVICE +Encryption succeeded, but done in software instead of the requested hardware. +.TP +.SM DESERR_HWERR +An error occurred in the hardware or driver. +.TP +.SM DESERR_BADPARAM +Bad parameter to routine. +.PD +.LP +Given a result status +.IR stat , +the macro +.SM DES_FAILED\c +.BR ( stat ) +is false only for the first two statuses. +.SH RESTRICTIONS +These routines are not available in RPCSRC 4.0. +This information is provided to describe the DES interface expected by +Secure RPC. diff --git a/lib/librpc/secure_rpc/man/keyenvoy.8c b/lib/librpc/secure_rpc/man/keyenvoy.8c new file mode 100644 index 000000000000..8cf7bc3a2ef8 --- /dev/null +++ b/lib/librpc/secure_rpc/man/keyenvoy.8c @@ -0,0 +1,22 @@ +.\" @(#)keyenvoy.8c	2.1 88/08/10 4.0 RPCSRC; from 1.5 88/03/01 SMI; +.TH KEYENVOY 8C "9 September 1987" +.SH NAME +keyenvoy \- talk to keyserver +.SH SYNOPSIS +.B keyenvoy +.SH DESCRIPTION +.IX "keyenvoy command" "" "\fLkeyenvoy\fP command" +.B keyenvoy +is used by some +.SM RPC +programs to talk to the key server, +.BR keyserv (8C). +The key server will not talk to anything but a root process, and +.B keyenvoy +is a set-uid root process that acts as an intermediary between a user +process that wishes to talk to the +key server and the key server itself. +.LP +This program cannot be run interactively. +.SH "SEE ALSO" +.BR keyserv (8C) diff --git a/lib/librpc/secure_rpc/man/keylogin.1 b/lib/librpc/secure_rpc/man/keylogin.1 new file mode 100644 index 000000000000..516d9deab6c7 --- /dev/null +++ b/lib/librpc/secure_rpc/man/keylogin.1 @@ -0,0 +1,32 @@ +.\" @(#)keylogin.1	2.1 88/08/10 4.0 RPCSRC; from 1.6 88/02/29 SMI; +.TH KEYLOGIN 1 "9 September 1987" +.SH NAME +keylogin \- decrypt and store secret key +.SH SYNOPSIS +.B keylogin +.SH DESCRIPTION +.IX "keylogin command" "" "\fLkeylogin\fR command"  +.LP +.B keylogin +prompts the user for their login password, and uses it do decrypt +the user's secret key stored in the +.BR publickey (5) +database. Once decrypted, the user's key is stored by the local +key server process +.BR keyserv (8C) +to be used by any secure network services, such as +.SM NFS\s0. +.LP +Normally, +.BR login (1) +does this work when the user logs onto the system, but running +.B keylogin +may be necessary if +the user did not type a password to +.BR login (1). +.SH "SEE ALSO" +.BR chkey (1), +.BR login (1), +.BR publickey (5), +.BR keyserv (8C), +.BR newkey (8) diff --git a/lib/librpc/secure_rpc/man/keyserv.8c b/lib/librpc/secure_rpc/man/keyserv.8c new file mode 100644 index 000000000000..aa153ed3fe41 --- /dev/null +++ b/lib/librpc/secure_rpc/man/keyserv.8c @@ -0,0 +1,52 @@ +.\" @(#)keyserv.8c	2.1 88/08/10 4.0 RPCSRC; from 1.6 88/03/01 SMI; +.TH KEYSERV 8C "9 September 1987" +.SH NAME +keyserv \- server for storing public and private keys +.SH SYNOPSIS +.B keyserv +[ +.B \-n +] +.SH DESCRIPTION +.IX "keyenvoy server" "" "\fLkeyenvoy\fP server" +.B keyserv +is a daemon that is used for storing the +private encryption keys of each +user logged into the system. These encryption +keys are using for accessing +secure network services such as secure +.SM NFS\s0. +When a user logs in to the system, the +.BR login(1) +program uses the login password to decrypt +the user's encryption key stored +in the Yellow Pages, and then gives the decrypted key to the +.B keyserv +daemon to store away. +.LP +Normally, root's key is read from the file +.B /etc/.rootkey +when the daemon starts up. This is useful during power-fail reboots +when no one is around to type a password, yet you still want the +secure network services to operate normally. +.SH OPTIONS +.TP +.B \-n +Do not read root's key from +.BR /etc/.rootkey . +Instead, prompt the user for the password to decrypt +.B root 's +key stored in the Yellow Pages and then store the decrypted key in +.B /etc/.rootkey +for future use. +This option is useful if the +.B /etc/.rootkey +file ever gets out of date or corrupted. +.SH FILES +.PD 0 +.TP 20 +.B /etc/.rootkey +.PD +.SH "SEE ALSO" +.BR login (1), +.BR publickey (5) diff --git a/lib/librpc/secure_rpc/man/publickey.3r b/lib/librpc/secure_rpc/man/publickey.3r new file mode 100644 index 000000000000..7063e8a43ccc --- /dev/null +++ b/lib/librpc/secure_rpc/man/publickey.3r @@ -0,0 +1,44 @@ +.\" @(#)publickey.3r	2.1 88/08/07 4.0 RPCSRC +.TH PUBLICKEY 3R  "6 October 1987" +.SH NAME +publickey, getpublickey, getsecretkey \- get public or secret key +.SH SYNOPSIS +.nf +.B #include <rpc/rpc.h> +.B #include <rpc/key_prot.h> +.LP +.B getpublickey(netname, publickey) +.B	char netname[\s-1MAXNETNAMELEN\s0+1]; +.B	char publickey[\s-1HEXKEYBYTES\s0+1]; +.LP +.B getsecretkey(netname, secretkey, passwd) +.B	char netname[\s-1MAXNETNAMELEN\s0+1]; +.B	char secretkey[\s-1HEXKEYBYTES\s0+1]; +.B	char *passwd; +.fi +.SH DESCRIPTION +.IX "getpublickey function" "" "\fLgetpublickey()\fP function" +.IX "getsecretkey function" "" "\fLgetsecretkey()\fP function" +These routines are used to get public and secret keys from the +.SM YP +database. +.B getsecretkey(\|) +has an extra argument, +.IR passwd , +which is used to decrypt the encrypted secret key stored in the database. +Both routines return 1 if they are successful in finding the key, 0 otherwise. +The keys are returned as +.SM NULL\s0-terminated, +hexadecimal strings. If the password supplied to +.B getsecretkey(\|) +fails to decrypt the secret key, the routine will return 1 but the +.I secretkey +argument will be a +.SM NULL +string (``''). +.SH "SEE ALSO" +.BR publickey (5) +.LP +.I \s-1RPC\s0 Programmer's Manual +in +.TX NETP diff --git a/lib/librpc/secure_rpc/man/publickey.5 b/lib/librpc/secure_rpc/man/publickey.5 new file mode 100644 index 000000000000..de3c1e99e779 --- /dev/null +++ b/lib/librpc/secure_rpc/man/publickey.5 @@ -0,0 +1,37 @@ +.\" @(#)publickey.5	2.1 88/08/07 4.0 RPCSRC; from 1.6 88/02/29 SMI; +.TH PUBLICKEY 5 "19 October 1987" +.SH NAME +publickey \- public key database +.SH SYNOPSIS +.B /etc/publickey +.SH DESCRIPTION +.LP +.B /etc/publickey +is the public key database used for secure +networking. Each entry in +the database consists of a network user +name (which may either refer to +a user or a hostname), followed by the user's +public key (in hex +notation), a colon, and then the user's +secret key encrypted with +its login password (also in hex notation). +.LP +This file is altered either by the user through the +.BR chkey (1) +command or by the system administrator through the +.BR newkey (8) +command. +The file +.B /etc/publickey +should only contain data on the Yellow +Pages master machine, where it +is converted into the +.SM YP +database +.BR publickey.byname . +.SH SEE ALSO +.BR chkey (1), +.BR publickey (3R), +.BR newkey (8), +.BR ypupdated (8C) diff --git a/lib/librpc/secure_rpc/man/rpc_secure.3n b/lib/librpc/secure_rpc/man/rpc_secure.3n new file mode 100644 index 000000000000..6e9a2ee362f8 --- /dev/null +++ b/lib/librpc/secure_rpc/man/rpc_secure.3n @@ -0,0 +1,330 @@ +.\" @(#)rpc_secure.3n	2.1 88/08/08 4.0 RPCSRC; from 1.19 88/06/24 SMI +.TH RPC 3N "16 February 1988" +.SH NAME +rpc_secure \- library routines for secure remote procedure calls +.SH SYNOPSIS AND DESCRIPTION +These routines are part of the RPC library.  They implement DES +Authentication.  See +.BR rpc (3N) +for further details about RPC. +.LP +.ft B +.nf +.sp .5 +#include <rpc/rpc.h> +.fi +.ft R +.br +.if t .ne 22 +.LP +.ft B +.nf +.sp .5 +\s-1AUTH\s0 * +authdes_create(name, window, syncaddr, ckey) +char *name; +unsigned window; +struct sockaddr_in *addr; +des_block *ckey; +.fi +.ft R +.IP +.B authdes_create(\|) +is the first of two routines which interface to the +.SM RPC +secure authentication system, known as +.SM DES +authentication. +The second is +.BR authdes_getucred(\|) , +below. Note: the keyserver daemon +.BR keyserv (8C) +must be running for the +.SM DES +authentication system to work. +.IP +.BR authdes_create(\|) , +used on the client side, returns an authentication handle that +will enable the use of the secure authentication system. +The first parameter +.I name +is the network name, or +.IR netname , +of the owner of the server process. This field usually +represents a +.I hostname +derived from the utility routine +.BR host2netname , +but could also represent a user name using +.BR user2netname . +The second field is window on the validity of +the client credential, given in seconds.  A small +window is more secure than a large one, but choosing +too small of a window will increase the frequency of +resynchronizations because of clock drift. The third +parameter +.I syncaddr +is optional.  If it is +.SM NULL\s0, +then the authentication system will assume +that the local clock is always in sync with the server's +clock, and will not attempt resynchronizations. If an address +is supplied, however, then the system will use the address +for consulting the remote time service whenever +resynchronization +is required. This parameter is usually the +address of the +.SM RPC +server itself. The final parameter +.I ckey +is also optional.  If it is +.SM NULL\s0, +then the authentication system will +generate a random +.SM DES +key to be used for the encryption of credentials. +If it is supplied, however, then it will be used instead. +.br +.if t .ne 13 +.LP +.ft B +.nf +.sp .5 +authdes_getucred(adc, uid, gid, grouplen, groups) +struct authdes_cred *adc; +short *uid; +short *gid; +short *grouplen; +int *groups; +.fi +.ft R +.IP +.BR authdes_getucred(\|) , +the second of the two +.SM DES +authentication routines, +is used on the server side for converting a +.SM DES +credential, which is +operating system independent, into a +.UX +credential. This routine differs from utility routine +.B netname2user +in that +.B authdes_getucred(\|) +pulls its information from a cache, and does not have to do a +Yellow Pages lookup every time it is called to get its information. +.br +.ft .ne 8 +.LP +.ft B +.nf +.sp .5 +host2netname(name, host, domain) +char *name; +char *host; +char *domain; +.fi +.ft R +.IP +Convert from a domain-specific hostname to an +operating-system independent netname. Return +.SM TRUE +if it succeeds and +.SM FALSE +if it fails. Inverse of +.BR netname2host(\|) . +.br +.if t .ne 9 +.LP +.ft B +.nf +.sp .5 +key_decryptsession(remotename, deskey) +char *remotename; +des_block *deskey; +.fi +.ft R +.IP +.B key_decryptsession(\|) +is an interface to the keyserver daemon, which is associated +with +.SM RPC\s0's +secure authentication system (\s-1DES\s0 +authentication). +User programs rarely need to call it, or its associated routines +.BR key_encryptsession(\|) , +.B key_gendes(\|) +and +.BR key_setsecret(\|) . +System commands such as +.B login +and the +.SM RPC +library are the main clients of these four routines. +.IP +.B key_decryptsession(\|) +takes a server netname and a des key, and decrypts the key by +using the the public key of the the server and the secret key +associated with the effective uid of the calling process.  It +is the inverse of +.BR key_encryptsession(\|) . +.br +.if t .ne 8 +.LP +.ft B +.nf +.sp .5 +key_encryptsession(remotename, deskey) +char *remotename; +des_block *deskey; +.fi +.ft R +.IP +.B key_encryptsession(\|) +is a keyserver interface routine. It +takes a server netname and a des key, and encrypts +it using the public key of the the server and the secret key +associated with the effective uid of the calling process.  It +is the inverse of +.BR key_decryptsession(\|) . +.br +.if t .ne 7 +.LP +.ft B +.nf +.sp .5 +key_gendes(deskey) +des_block *deskey; +.fi +.ft R +.IP +.B key_gendes(\|) +is a keyserver interface routine. It +is used to ask the keyserver for a secure conversation key. +Choosing one at \(lqrandom\(rq is usually not good enough, +because +the common ways of choosing random numbers, such as using the +current time, are very easy to guess. +.br +.if t .ne 6 +.LP +.ft B +.nf +.sp .5 +key_setsecret(key) +char *key; +.fi +.ft R +.IP +.B key_setsecret(\|) +is a keyserver interface routine. It is used to set the key for +the effective +.I uid +of the calling process. +.br +.if t .ne 7 +.LP +.ft B +.nf +.sp .5 +getnetname(name) +char name[\s-1MAXNETNAMELEN\s0]; +.fi +.ft R +.IP +.B getnetname(\|) +installs the unique, operating-system independent netname of +the +caller in the fixed-length array +.IR name . +Returns +.SM TRUE +if it succeeds and +.SM FALSE +if it fails. +.br +.if t .ne 6 +.LP +.ft B +.nf +.sp .5 +netname2host(name, host, hostlen) +char *name; +char *host; +int hostlen; +.fi +.ft R +.IP +Convert from an operating-system independent netname to a +domain-specific hostname. Returns +.SM TRUE +if it succeeds and +.SM FALSE +if it fails.  Inverse of +.BR host2netname(\|) . +.br +.if t .ne 9 +.LP +.ft B +.nf +.sp .5 +netname2user(name, uidp, gidp, gidlenp, gidlist) +char *name; +int *uidp; +int *gidp; +int *gidlenp; +int *gidlist; +.fi +.ft R +.IP +Convert from an operating-system independent netname to a +domain-specific user +.SM ID. +Returns +.SM TRUE +if it succeeds and +.SM FALSE +if it fails. Inverse of +.BR user2netname(\|) . +.br +.if t .ne 8 +.LP +.ft B +.nf +.sp .5 +user2netname(name, uid, domain) +char *name; +int uid; +char *domain; +.fi +.ft R +.IP +Convert from a domain-specific username to an operating-system +independent netname. Returns +.SM TRUE +if it succeeds and +.SM FALSE +if it fails. Inverse of +.BR netname2user(\|) . +.br +.SH SEE ALSO +.BR xdr (3N), +.BR keyserv (8C), +.BR rpc (3N) +.br +The following manuals: +.RS +.ft I +Remote Procedure Calls: Protocol Specification +.br +Remote Procedure Call Programming Guide +.br +rpcgen Programming Guide +.br +.ft R +.RE +.IR "\s-1RPC\s0: Remote Procedure Call Protocol Specification" , +.SM RFC1050, Sun Microsystems, Inc., +.SM USC-ISI\s0. + diff --git a/lib/librpc/secure_rpc/man/rtime.3n b/lib/librpc/secure_rpc/man/rtime.3n new file mode 100644 index 000000000000..af0c1ca15960 --- /dev/null +++ b/lib/librpc/secure_rpc/man/rtime.3n @@ -0,0 +1,43 @@ +.\" @(#)rtime.3n	2.1 88/08/08 4.0 RPCSRC; from 1.5 88/02/08 SMI +.TH RTIME 3  "22 November 1987" +.SH NAME +rtime \- get remote time +.SH SYNOPSIS +.nf +.B #include <sys/types.h> +.B #include <sys/time.h> +.B #include <netinet/in.h> +.LP +.B int rtime(addrp, timep, timeout) +.B struct sockaddr_in \(**addrp; +.B struct timeval \(**timep; +.B struct timeval \(**timeout; +.fi +.SH DESCRIPTION +.B rtime(\|) +consults the Internet Time Server at the address pointed to by +.I addrp +and returns the remote time in the +.B timeval +struct pointed to by +.IR timep . +Normally, the +.SM UDP +protocol is used when consulting the Time Server. The +.I timeout +parameter specifies how long the +routine should wait before giving +up when waiting for a reply.  If +.I timeout +is specified as +.SM NULL\s0, +however, the routine will instead use +.SM TCP +and block until a reply is received from the time server. +.LP +The routine returns 0 if it is successful. Otherwise, +it returns \-1 and +.B errno +is set to reflect the cause of the error. +.SH "SEE ALSO" +.BR timed (8c) diff --git a/lib/librpc/secure_rpc/rpc/Makefile b/lib/librpc/secure_rpc/rpc/Makefile new file mode 100644 index 000000000000..88b242fcf28f --- /dev/null +++ b/lib/librpc/secure_rpc/rpc/Makefile @@ -0,0 +1,109 @@ +# +# @(#)Makefile	2.3 88/08/15 4.0 RPCSRC +# +# +# Copyright (c) 1987 by Sun Microsystems, Inc. +# + +DESTDIR= + +CFLAGS = -I.. + +SRCS = auth_des.c authdes_prot.c key_call.c key_prot.c netname.c svcauth_des.c \ +	openchild.c rtime.c publickey.c xcrypt.c \ +	auth_none.c auth_unix.c  authunix_prot.c bindresvport.c \ +	clnt_generic.c clnt_perror.c clnt_raw.c clnt_simple.c clnt_tcp.c \ +	clnt_udp.c rpc_dtablesize.c get_myaddress.c getrpcent.c getrpcport.c \ +	pmap_clnt.c pmap_getmaps.c pmap_getport.c pmap_prot.c \ +	pmap_prot2.c pmap_rmt.c rpc_prot.c rpc_commondata.c rpc_callmsg.c \ +	svc.c svc_auth.c svc_auth_unix.c svc_raw.c svc_run.c svc_simple.c \ +	svc_tcp.c svc_udp.c xdr.c xdr_array.c xdr_float.c xdr_mem.c \ +	xdr_rec.c xdr_reference.c xdr_stdio.c + +OBJS = auth_des.o authdes_prot.o key_call.o key_prot.o netname.o svcauth_des.o \ +	openchild.o rtime.o publickey.o xcrypt.o \ +	auth_none.o auth_unix.o  authunix_prot.o bindresvport.o \ +	clnt_generic.o clnt_perror.o clnt_raw.o clnt_simple.o clnt_tcp.o \ +	clnt_udp.o rpc_dtablesize.o get_myaddress.o getrpcent.o getrpcport.o \ +	pmap_clnt.o pmap_getmaps.o pmap_getport.o pmap_prot.o \ +	pmap_prot2.o pmap_rmt.o rpc_prot.o rpc_commondata.o rpc_callmsg.o \ +	svc.o svc_auth.o svc_auth_unix.o svc_raw.o svc_run.o svc_simple.o \ +	svc_tcp.o svc_udp.o xdr.o xdr_array.o xdr_float.o xdr_mem.o \ +	xdr_rec.o xdr_reference.o xdr_stdio.o + +HDRS = key_prot.h \ +	auth.h auth_unix.h auth_des.h clnt.h netdb.h pmap_clnt.h \ +	pmap_prot.h pmap_rmt.h rpc.h rpc_msg.h svc.h svc_auth.h types.h xdr.h + +XFILES= key_prot.x + +all rpclib:	librpclib.a + +librpclib.a: ${OBJS} +	@echo "building librpclib.a" +	@ar cru librpclib.a ${OBJS} + +install: $(HDRS) librpclib.a +	@echo "Creating RPC header directory" +	-mkdir ${DESTDIR}/usr/include/rpc && \ +		chown bin ${DESTDIR}/usr/include/rpc && \ +		chmod 755 ${DESTDIR}/usr/include/rpc +	@echo "Installing RPC header files" +	-set -x;for i in $(HDRS) $(XFILES) ; do \ +		(install -c -m 644 $$i ${DESTDIR}/usr/include/rpc) done +	@echo "Installing RPC library" +	install -c -m 644 librpclib.a ${DESTDIR}/usr/lib +	ranlib ${DESTDIR}/usr/lib/librpclib.a + +tags: $(SRCS) $(HDRS) +	ctags -tw $(SRCS) $(HDRS) + +ref: tags +	sed 's,	/.*,,' tags | \ +	awk ' { printf("%-26s%-16s%s\n", $$1, $$2, $$3) }' > ref + +lint: $(SRCS) $(HDRS) +	$(LINT.c) $(SRCS) + +clean: rm -f *.o rpclib.a + +.SUFFIXES: .x .x~ + +.x.c: +	rpcgen -c $< | \ +	sed 's/^#include \"$*\.h\"/#include <rpc\/$*\.h>/' > $@ + +.x.h: +	rpcgen -h $< > $@ + +depend: $(SRCS) $(HDRS) +	@${CC} ${CFLAGS} -M ${SRCS} > makedep +	@echo '/^# DO NOT DELETE THIS LINE/+1,$$d' >eddep +	@echo '$$r makedep' >>eddep +	@echo 'w' >>eddep +	@cp Makefile makefile.bak +	@ed - Makefile < eddep +	@rm eddep makedep makefile.bak + +depend.42BSD depend.42bsd: +	cp /dev/null x.c +	for i in $(SRCS) ; do \ +              (/bin/grep '^#[         ]*include' x.c $$i | sed \ +                      -e '/\.\.\/h/d' \ +                      -e '/\.\.\/ufs/d' \ +                      -e 's,<\(.*\)>,"/usr/include/\1",' \ +                      -e 's/:[^"]*"\([^"]*\)".*/: \1/' \ +	                  -e 's/\.c/\.o/' >>makedep); done +	echo '/^# DO NOT DELETE THIS LINE/+2,$$d' >eddep +	echo '$$r makedep' >>eddep +	echo 'w' >>eddep +	cp Makefile Makefile.bak +	ed - Makefile < eddep +	rm eddep makedep x.c +	echo '# DEPENDENCIES MUST END AT END OF FILE' >> Makefile +	echo '# IF YOU PUT STUFF HERE IT WILL GO AWAY' >> Makefile +	echo '# see make depend above' >> Makefile + +# DO NOT DELETE THIS LINE + + diff --git a/lib/librpc/secure_rpc/rpc/auth_des.c b/lib/librpc/secure_rpc/rpc/auth_des.c new file mode 100644 index 000000000000..a757c498a99e --- /dev/null +++ b/lib/librpc/secure_rpc/rpc/auth_des.c @@ -0,0 +1,411 @@ +#if defined(LIBC_SCCS) && !defined(lint) +static char sccsid[] = 	"@(#)auth_des.c	2.2 88/07/29 4.0 RPCSRC; from 1.9 88/02/08 SMI"; +#endif +/* + * Sun RPC is a product of Sun Microsystems, Inc. and is provided for + * unrestricted use provided that this legend is included on all tape + * media and as a part of the software program in whole or part.  Users + * may copy or modify Sun RPC without charge, but are not authorized + * to license or distribute it to anyone else except as part of a product or + * program developed by the user. + *  + * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE + * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR + * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. + *  + * Sun RPC is provided with no support and without any obligation on the + * part of Sun Microsystems, Inc. to assist in its use, correction, + * modification or enhancement. + *  + * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE + * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC + * OR ANY PART THEREOF. + *  + * In no event will Sun Microsystems, Inc. be liable for any lost revenue + * or profits or other special, indirect and consequential damages, even if + * Sun has been advised of the possibility of such damages. + *  + * Sun Microsystems, Inc. + * 2550 Garcia Avenue + * Mountain View, California  94043 + */ +/* + * Copyright (c) 1988 by Sun Microsystems, Inc. + */ +/* + * auth_des.c, client-side implementation of DES authentication + */ + +#include <des_crypt.h> +#include <rpc/types.h> +#include <rpc/auth.h> +#include <rpc/auth_des.h> +#include <rpc/xdr.h> +#include <netinet/in.h>	/* XXX: just to get htonl() and ntohl() */ +#include <sys/socket.h> + +#define MILLION		1000000L +#define RTIME_TIMEOUT 5		/* seconds to wait for sync */ + +#define AUTH_PRIVATE(auth)	(struct ad_private *) auth->ah_private +#define ALLOC(object_type)	(object_type *) mem_alloc(sizeof(object_type)) +#define FREE(ptr, size)		mem_free((char *)(ptr), (int) size) +#define ATTEMPT(xdr_op)		if (!(xdr_op)) return (FALSE) + +#define debug(msg)		 /*printf("%s\n", msg) */ + +/*  + * DES authenticator operations vector + */ +static void	authdes_nextverf(); +static bool_t	authdes_marshal(); +static bool_t	authdes_validate(); +static bool_t	authdes_refresh(); +static void	authdes_destroy(); +static struct auth_ops authdes_ops = { +	authdes_nextverf, +	authdes_marshal, +	authdes_validate, +	authdes_refresh, +	authdes_destroy +}; + + +/* + * This struct is pointed to by the ah_private field of an "AUTH *" + */ +struct ad_private { +	char *ad_fullname; 		/* client's full name */ +	u_int ad_fullnamelen;		/* length of name, rounded up */ +	char *ad_servername; 		/* server's full name */ +	u_int ad_servernamelen;		/* length of name, rounded up */ +	u_int ad_window;	  	/* client specified window */ +	bool_t ad_dosync;		/* synchronize? */		 +	struct sockaddr ad_syncaddr;	/* remote host to synch with */ +	struct timeval ad_timediff;	/* server's time - client's time */ +	u_long ad_nickname;		/* server's nickname for client */ +	struct authdes_cred ad_cred;	/* storage for credential */ +	struct authdes_verf ad_verf;	/* storage for verifier */ +	struct timeval ad_timestamp;	/* timestamp sent */ +	des_block ad_xkey;		/* encrypted conversation key */ +}; +	 + +/* + * Create the client des authentication object + */	 +AUTH * +authdes_create(servername, window, syncaddr, ckey) +	char *servername;		/* network name of server */ +	u_int window;			/* time to live */ +	struct sockaddr *syncaddr;	/* optional addr of host to sync with */ +	des_block *ckey;		/* optional conversation key to use*/ +{ + +	AUTH *auth; +	struct ad_private *ad; +	char namebuf[MAXNETNAMELEN+1]; + +	/* + 	 * Allocate everything now +	 */ +	auth = ALLOC(AUTH); +	ad = ALLOC(struct ad_private); +	(void) getnetname(namebuf); + +	ad->ad_fullnamelen = RNDUP(strlen(namebuf)); +	ad->ad_fullname = mem_alloc(ad->ad_fullnamelen + 1); + +	ad->ad_servernamelen = strlen(servername); +	ad->ad_servername = mem_alloc(ad->ad_servernamelen + 1); + +	if (auth == NULL || ad == NULL || ad->ad_fullname == NULL || +	    ad->ad_servername == NULL) { +		debug("authdes_create: out of memory"); +		goto failed; +	} + +	/*  +	 * Set up private data +	 */ +	bcopy(namebuf, ad->ad_fullname, ad->ad_fullnamelen + 1); +	bcopy(servername, ad->ad_servername, ad->ad_servernamelen + 1); +	if (syncaddr != NULL) { +		ad->ad_syncaddr = *syncaddr; +		ad->ad_dosync = TRUE; +	} else { +		ad->ad_dosync = FALSE; +	} +	ad->ad_window = window; +	if (ckey == NULL) { +		if (key_gendes(&auth->ah_key) < 0) { +			debug("authdes_create: unable to gen conversation key"); +			return (NULL); +		} +	} else { +		auth->ah_key = *ckey; +	} + +	/* +	 * Set up auth handle +	 */  +	auth->ah_cred.oa_flavor = AUTH_DES; +	auth->ah_verf.oa_flavor = AUTH_DES; +	auth->ah_ops = &authdes_ops; +	auth->ah_private = (caddr_t)ad; + +	if (!authdes_refresh(auth)) { +		goto failed; +	}	 +	return (auth); + +failed: +	if (auth != NULL)  +		FREE(auth, sizeof(AUTH));  +	if (ad != NULL)  +		FREE(ad, sizeof(struct ad_private)); +	if (ad->ad_fullname != NULL)  +		FREE(ad->ad_fullname, ad->ad_fullnamelen + 1); +	if (ad->ad_servername != NULL)  +		FREE(ad->ad_servername, ad->ad_servernamelen + 1); +	return (NULL); +} + +/* + * Implement the five authentication operations + */ + + +/* + * 1. Next Verifier + */	 +/*ARGSUSED*/ +static void +authdes_nextverf(auth) +	AUTH *auth; +{ +	/* what the heck am I supposed to do??? */ +} +		 + + +/* + * 2. Marshal + */ +static bool_t +authdes_marshal(auth, xdrs) +	AUTH *auth; +	XDR *xdrs; +{ +	struct ad_private *ad = AUTH_PRIVATE(auth); +	struct authdes_cred *cred = &ad->ad_cred; +	struct authdes_verf *verf = &ad->ad_verf; +	des_block cryptbuf[2];	 +	des_block ivec; +	int status; +	int len; +	register long *ixdr; + +	/* +	 * Figure out the "time", accounting for any time difference +	 * with the server if necessary. +	 */ +	(void) gettimeofday(&ad->ad_timestamp, (struct timezone *)NULL); +	ad->ad_timestamp.tv_sec += ad->ad_timediff.tv_sec; +	ad->ad_timestamp.tv_usec += ad->ad_timediff.tv_usec; +	if (ad->ad_timestamp.tv_usec >= MILLION) { +		ad->ad_timestamp.tv_usec -= MILLION; +		ad->ad_timestamp.tv_sec += 1; +	} + +	/* +	 * XDR the timestamp and possibly some other things, then +	 * encrypt them. +	 */ +	ixdr = (long *)cryptbuf; +	IXDR_PUT_LONG(ixdr, ad->ad_timestamp.tv_sec); +	IXDR_PUT_LONG(ixdr, ad->ad_timestamp.tv_usec); +	if (ad->ad_cred.adc_namekind == ADN_FULLNAME) { +		IXDR_PUT_U_LONG(ixdr, ad->ad_window); +		IXDR_PUT_U_LONG(ixdr, ad->ad_window - 1); +		ivec.key.high = ivec.key.low = 0;	 +		status = cbc_crypt((char *)&auth->ah_key, (char *)cryptbuf,  +			2*sizeof(des_block), DES_ENCRYPT | DES_HW, (char *)&ivec); +	} else { +		status = ecb_crypt((char *)&auth->ah_key, (char *)cryptbuf,  +			sizeof(des_block), DES_ENCRYPT | DES_HW); +	} +	if (DES_FAILED(status)) { +		debug("authdes_marshal: DES encryption failure"); +		return (FALSE); +	} +	ad->ad_verf.adv_xtimestamp = cryptbuf[0]; +	if (ad->ad_cred.adc_namekind == ADN_FULLNAME) { +		ad->ad_cred.adc_fullname.window = cryptbuf[1].key.high; +		ad->ad_verf.adv_winverf = cryptbuf[1].key.low; +	} else { +		ad->ad_cred.adc_nickname = ad->ad_nickname; +		ad->ad_verf.adv_winverf = 0; +	} + +	/* +	 * Serialize the credential and verifier into opaque +	 * authentication data. +	 */ +	if (ad->ad_cred.adc_namekind == ADN_FULLNAME) { +		len = ((1 + 1 + 2 + 1)*BYTES_PER_XDR_UNIT + ad->ad_fullnamelen); +	} else { +		len = (1 + 1)*BYTES_PER_XDR_UNIT; +	} + +	if (ixdr = xdr_inline(xdrs, 2*BYTES_PER_XDR_UNIT)) { +		IXDR_PUT_LONG(ixdr, AUTH_DES); +		IXDR_PUT_LONG(ixdr, len); +	} else { +		ATTEMPT(xdr_putlong(xdrs, &auth->ah_cred.oa_flavor));  +		ATTEMPT(xdr_putlong(xdrs, &len));  +	} +	ATTEMPT(xdr_authdes_cred(xdrs, cred)); + +	len = (2 + 1)*BYTES_PER_XDR_UNIT;  +	if (ixdr = xdr_inline(xdrs, 2*BYTES_PER_XDR_UNIT)) { +		IXDR_PUT_LONG(ixdr, AUTH_DES); +		IXDR_PUT_LONG(ixdr, len); +	} else { +		ATTEMPT(xdr_putlong(xdrs, &auth->ah_verf.oa_flavor));  +		ATTEMPT(xdr_putlong(xdrs, &len));  +	} +	ATTEMPT(xdr_authdes_verf(xdrs, verf)); +	return (TRUE); +} + + +/* + * 3. Validate + */ +static bool_t +authdes_validate(auth, rverf) +	AUTH *auth; +	struct opaque_auth *rverf; +{ +	struct ad_private *ad = AUTH_PRIVATE(auth); +	struct authdes_verf verf; +	int status; +	register u_long *ixdr; + +	if (rverf->oa_length != (2 + 1) * BYTES_PER_XDR_UNIT) { +		return (FALSE); +	} +	ixdr = (u_long *)rverf->oa_base; +	verf.adv_xtimestamp.key.high = (u_long)*ixdr++; +	verf.adv_xtimestamp.key.low = (u_long)*ixdr++; +	verf.adv_int_u = (u_long)*ixdr++;	/* nickname not XDR'd ! */ + +	/* +	 * Decrypt the timestamp +	 */ +	status = ecb_crypt((char *)&auth->ah_key, (char *)&verf.adv_xtimestamp, +		sizeof(des_block), DES_DECRYPT | DES_HW); + +	if (DES_FAILED(status)) { +		debug("authdes_validate: DES decryption failure"); +		return (FALSE); +	} + +	/* +	 * xdr the decrypted timestamp  +	 */ +	ixdr = (u_long *)verf.adv_xtimestamp.c; +	verf.adv_timestamp.tv_sec = IXDR_GET_LONG(ixdr) + 1; +	verf.adv_timestamp.tv_usec = IXDR_GET_LONG(ixdr); + +	/* +	 * validate +	 */ +	if (bcmp((char *)&ad->ad_timestamp, (char *)&verf.adv_timestamp, +		 sizeof(struct timeval)) != 0) { +		debug("authdes_validate: verifier mismatch\n"); +		return (FALSE); +	} + +	/* +	 * We have a nickname now, let's use it +	 */ +	ad->ad_nickname = verf.adv_nickname;	 +	ad->ad_cred.adc_namekind = ADN_NICKNAME;  +	return (TRUE);	 +} + +/* + * 4. Refresh + */ +static bool_t +authdes_refresh(auth) +	AUTH *auth; +{ +	struct ad_private *ad = AUTH_PRIVATE(auth); +	struct authdes_cred *cred = &ad->ad_cred; + +	if (ad->ad_dosync &&  +			!synchronize(&ad->ad_syncaddr, &ad->ad_timediff)) { +		/* +		 * Hope the clocks are synced! +		 */ +		ad->ad_timediff.tv_sec = ad->ad_timediff.tv_usec = 0; +		debug("authdes_refresh: unable to synchronize with server"); +	} +	ad->ad_xkey = auth->ah_key; +	if (key_encryptsession(ad->ad_servername, &ad->ad_xkey) < 0) { +		debug("authdes_create: unable to encrypt conversation key"); +		return (FALSE); +	} +	cred->adc_fullname.key = ad->ad_xkey; +	cred->adc_namekind = ADN_FULLNAME; +	cred->adc_fullname.name = ad->ad_fullname; +	return (TRUE); +} + + +/* + * 5. Destroy + */ +static void +authdes_destroy(auth) +	AUTH *auth; +{ +	struct ad_private *ad = AUTH_PRIVATE(auth); + +	FREE(ad->ad_fullname, ad->ad_fullnamelen + 1); +	FREE(ad->ad_servername, ad->ad_servernamelen + 1); +	FREE(ad, sizeof(struct ad_private)); +	FREE(auth, sizeof(AUTH)); +} +	 + + +/* + * Synchronize with the server at the given address, that is, + * adjust timep to reflect the delta between our clocks + */ +static bool_t +synchronize(syncaddr, timep) +	struct sockaddr *syncaddr; +	struct timeval *timep; +{ +	struct timeval mytime; +	struct timeval timeout; + +	timeout.tv_sec = RTIME_TIMEOUT; +	timeout.tv_usec = 0; +	if (rtime((struct sockaddr_in *)syncaddr, timep, &timeout) < 0) { +		return (FALSE); +	} +	(void) gettimeofday(&mytime, (struct timezone *)NULL); +	timep->tv_sec -= mytime.tv_sec; +	if (mytime.tv_usec > timep->tv_usec) { +		timep->tv_sec -= 1; +		timep->tv_usec += MILLION; +	} +	timep->tv_usec -= mytime.tv_usec; +	return (TRUE); +} diff --git a/lib/librpc/secure_rpc/rpc/auth_des.h b/lib/librpc/secure_rpc/rpc/auth_des.h new file mode 100644 index 000000000000..4ae476123432 --- /dev/null +++ b/lib/librpc/secure_rpc/rpc/auth_des.h @@ -0,0 +1,105 @@ +/*	@(#)auth_des.h	2.2 88/07/29 4.0 RPCSRC; from 1.3 88/02/08 SMI */ +/* + * Sun RPC is a product of Sun Microsystems, Inc. and is provided for + * unrestricted use provided that this legend is included on all tape + * media and as a part of the software program in whole or part.  Users + * may copy or modify Sun RPC without charge, but are not authorized + * to license or distribute it to anyone else except as part of a product or + * program developed by the user. + *  + * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE + * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR + * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. + *  + * Sun RPC is provided with no support and without any obligation on the + * part of Sun Microsystems, Inc. to assist in its use, correction, + * modification or enhancement. + *  + * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE + * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC + * OR ANY PART THEREOF. + *  + * In no event will Sun Microsystems, Inc. be liable for any lost revenue + * or profits or other special, indirect and consequential damages, even if + * Sun has been advised of the possibility of such damages. + *  + * Sun Microsystems, Inc. + * 2550 Garcia Avenue + * Mountain View, California  94043 + */ + +/* + * Copyright (c) 1988 by Sun Microsystems, Inc. + */ + +/* + * auth_des.h, Protocol for DES style authentication for RPC + */ + +#ifndef _AUTH_DES_ +#define _AUTH_DES_ + +/* + * There are two kinds of "names": fullnames and nicknames + */ +enum authdes_namekind { +	ADN_FULLNAME,  +	ADN_NICKNAME +}; + +/* + * A fullname contains the network name of the client,  + * a conversation key and the window + */ +struct authdes_fullname { +	char *name;		/* network name of client, up to MAXNETNAMELEN */ +	des_block key;		/* conversation key */ +	u_long window;		/* associated window */ +}; + + +/* + * A credential  + */ +struct authdes_cred { +	enum authdes_namekind adc_namekind; +	struct authdes_fullname adc_fullname; +	u_long adc_nickname; +}; + + + +/* + * A des authentication verifier  + */ +struct authdes_verf { +	union { +		struct timeval adv_ctime;	/* clear time */ +		des_block adv_xtime;		/* crypt time */ +	} adv_time_u; +	u_long adv_int_u; +}; + +/* + * des authentication verifier: client variety + * + * adv_timestamp is the current time. + * adv_winverf is the credential window + 1. + * Both are encrypted using the conversation key. + */ +#define adv_timestamp	adv_time_u.adv_ctime +#define adv_xtimestamp	adv_time_u.adv_xtime +#define adv_winverf	adv_int_u + +/* + * des authentication verifier: server variety + * + * adv_timeverf is the client's timestamp + client's window + * adv_nickname is the server's nickname for the client. + * adv_timeverf is encrypted using the conversation key. + */ +#define adv_timeverf	adv_time_u.adv_ctime +#define adv_xtimeverf	adv_time_u.adv_xtime +#define adv_nickname	adv_int_u + +#endif /* ndef _AUTH_DES_ */ diff --git a/lib/librpc/secure_rpc/rpc/authdes_prot.c b/lib/librpc/secure_rpc/rpc/authdes_prot.c new file mode 100644 index 000000000000..14679c00a9cc --- /dev/null +++ b/lib/librpc/secure_rpc/rpc/authdes_prot.c @@ -0,0 +1,82 @@ +#if defined(LIBC_SCCS) && !defined(lint) +static char sccsid[] = 	"@(#)authdes_prot.c	2.1 88/07/29 4.0 RPCSRC; from 1.6 88/02/08 SMI"; +#endif +/* + * Sun RPC is a product of Sun Microsystems, Inc. and is provided for + * unrestricted use provided that this legend is included on all tape + * media and as a part of the software program in whole or part.  Users + * may copy or modify Sun RPC without charge, but are not authorized + * to license or distribute it to anyone else except as part of a product or + * program developed by the user. + *  + * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE + * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR + * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. + *  + * Sun RPC is provided with no support and without any obligation on the + * part of Sun Microsystems, Inc. to assist in its use, correction, + * modification or enhancement. + *  + * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE + * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC + * OR ANY PART THEREOF. + *  + * In no event will Sun Microsystems, Inc. be liable for any lost revenue + * or profits or other special, indirect and consequential damages, even if + * Sun has been advised of the possibility of such damages. + *  + * Sun Microsystems, Inc. + * 2550 Garcia Avenue + * Mountain View, California  94043 + */ +/* + * Copyright (c) 1988 by Sun Microsystems, Inc. + */ + +/* + * authdes_prot.c, XDR routines for DES authentication + */ + +#include <rpc/types.h> +#include <rpc/xdr.h> +#include <rpc/auth.h> +#include <rpc/auth_des.h> + +#define ATTEMPT(xdr_op) if (!(xdr_op)) return (FALSE) + +bool_t +xdr_authdes_cred(xdrs, cred) +	XDR *xdrs; +	struct authdes_cred *cred; +{ +	/* +	 * Unrolled xdr +	 */ +	ATTEMPT(xdr_enum(xdrs, (enum_t *)&cred->adc_namekind)); +	switch (cred->adc_namekind) { +	case ADN_FULLNAME: +		ATTEMPT(xdr_string(xdrs, &cred->adc_fullname.name, MAXNETNAMELEN)); +		ATTEMPT(xdr_opaque(xdrs, (caddr_t)&cred->adc_fullname.key, sizeof(des_block))); +		ATTEMPT(xdr_opaque(xdrs, (caddr_t)&cred->adc_fullname.window, sizeof(cred->adc_fullname.window))); +		return (TRUE); +	case ADN_NICKNAME: +		ATTEMPT(xdr_opaque(xdrs, (caddr_t)&cred->adc_nickname, sizeof(cred->adc_nickname))); +		return (TRUE); +	default: +		return (FALSE); +	} +} + + +bool_t +xdr_authdes_verf(xdrs, verf) +	register XDR *xdrs; +	register struct authdes_verf *verf;	 +{ +	/* + 	 * Unrolled xdr + 	 */ +	ATTEMPT(xdr_opaque(xdrs, (caddr_t)&verf->adv_xtimestamp, sizeof(des_block))); +	ATTEMPT(xdr_opaque(xdrs, (caddr_t)&verf->adv_int_u, sizeof(verf->adv_int_u))); +	return (TRUE); +} diff --git a/lib/librpc/secure_rpc/rpc/key_call.c b/lib/librpc/secure_rpc/rpc/key_call.c new file mode 100644 index 000000000000..c2fd3354d042 --- /dev/null +++ b/lib/librpc/secure_rpc/rpc/key_call.c @@ -0,0 +1,228 @@ +#if defined(LIBC_SCCS) && !defined(lint) +static char sccsid[] = 	"@(#)key_call.c	2.2 88/08/15 4.0 RPCSRC; from 1.11 88/02/08 SMI"; +#endif +/* + * Copyright (c) 1988 by Sun Microsystems, Inc. + */ +/* + * Sun RPC is a product of Sun Microsystems, Inc. and is provided for + * unrestricted use provided that this legend is included on all tape + * media and as a part of the software program in whole or part.  Users + * may copy or modify Sun RPC without charge, but are not authorized + * to license or distribute it to anyone else except as part of a product or + * program developed by the user. + *  + * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE + * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR + * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. + *  + * Sun RPC is provided with no support and without any obligation on the + * part of Sun Microsystems, Inc. to assist in its use, correction, + * modification or enhancement. + *  + * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE + * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC + * OR ANY PART THEREOF. + *  + * In no event will Sun Microsystems, Inc. be liable for any lost revenue + * or profits or other special, indirect and consequential damages, even if + * Sun has been advised of the possibility of such damages. + *  + * Sun Microsystems, Inc. + * 2550 Garcia Avenue + * Mountain View, California  94043 + */ + +/* + * key_call.c, Interface to keyserver + * + * setsecretkey(key) - set your secret key + * encryptsessionkey(agent, deskey) - encrypt a session key to talk to agent + * decryptsessionkey(agent, deskey) - decrypt ditto + * gendeskey(deskey) - generate a secure des key + * netname2user(...) - get unix credential for given name (kernel only) + */ +#include <sys/param.h> +#include <sys/socket.h> +#include <rpc/rpc.h> +#include <rpc/key_prot.h> + +#define KEY_TIMEOUT	5	/* per-try timeout in seconds */ +#define KEY_NRETRY	12	/* number of retries */ + +#define debug(msg)		/* turn off debugging */ + +static struct timeval trytimeout = { KEY_TIMEOUT, 0 }; +static struct timeval tottimeout = { KEY_TIMEOUT * KEY_NRETRY, 0 }; + +key_setsecret(secretkey) +	char *secretkey; +{ +	keystatus status; + +	if (!key_call((u_long)KEY_SET, xdr_keybuf, secretkey, xdr_keystatus,  +		(char*)&status))  +	{ +		return (-1); +	} +	if (status != KEY_SUCCESS) { +		debug("set status is nonzero"); +		return (-1); +	} +	return (0); +} + + +key_encryptsession(remotename, deskey) +	char *remotename; +	des_block *deskey; +{ +	cryptkeyarg arg; +	cryptkeyres res; + +	arg.remotename = remotename; +	arg.deskey = *deskey; +	if (!key_call((u_long)KEY_ENCRYPT,  +		xdr_cryptkeyarg, (char *)&arg, xdr_cryptkeyres, (char *)&res))  +	{ +		return (-1); +	} +	if (res.status != KEY_SUCCESS) { +		debug("encrypt status is nonzero"); +		return (-1); +	} +	*deskey = res.cryptkeyres_u.deskey; +	return (0); +} + + +key_decryptsession(remotename, deskey) +	char *remotename; +	des_block *deskey; +{ +	cryptkeyarg arg; +	cryptkeyres res; + +	arg.remotename = remotename; +	arg.deskey = *deskey; +	if (!key_call((u_long)KEY_DECRYPT,  +		xdr_cryptkeyarg, (char *)&arg, xdr_cryptkeyres, (char *)&res))   +	{ +		return (-1); +	} +	if (res.status != KEY_SUCCESS) { +		debug("decrypt status is nonzero"); +		return (-1); +	} +	*deskey = res.cryptkeyres_u.deskey; +	return (0); +} + +key_gendes(key) +	des_block *key; +{ +	struct sockaddr_in sin; +	CLIENT *client; +	int socket; +	enum clnt_stat stat; + +  +	sin.sin_family = AF_INET; +	sin.sin_port = 0; +	sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK); +	bzero(sin.sin_zero, sizeof(sin.sin_zero)); +	socket = RPC_ANYSOCK; +	client = clntudp_bufcreate(&sin, (u_long)KEY_PROG, (u_long)KEY_VERS, +		trytimeout, &socket, RPCSMALLMSGSIZE, RPCSMALLMSGSIZE); +	if (client == NULL) { +		return (-1); +	} +	stat = clnt_call(client, KEY_GEN, xdr_void, NULL, +		xdr_des_block, key, tottimeout); +	clnt_destroy(client); +	(void) close(socket); +	if (stat != RPC_SUCCESS) { +		return (-1); +	} +	return (0); +} + + +#include <stdio.h> +#include <sys/wait.h> + +  +static +key_call(proc, xdr_arg, arg, xdr_rslt, rslt) +	u_long proc; +	bool_t (*xdr_arg)(); +	char *arg; +	bool_t (*xdr_rslt)(); +	char *rslt; +{ +	XDR xdrargs; +	XDR xdrrslt; +	FILE *fargs; +	FILE *frslt; +	int (*osigchild)(); +	union wait status; +	int pid; +	int success; +	int ruid; +	int euid; +	static char MESSENGER[] = "/usr/etc/keyenvoy"; + +	success = 1; +	osigchild = signal(SIGCHLD, SIG_IGN); + +	/* +	 * We are going to exec a set-uid program which makes our effective uid +	 * zero, and authenticates us with our real uid. We need to make the  +	 * effective uid be the real uid for the setuid program, and  +	 * the real uid be the effective uid so that we can change things back. +	 */ +	euid = geteuid(); +	ruid = getuid(); +	(void) setreuid(euid, ruid); +	pid = _openchild(MESSENGER, &fargs, &frslt); +	(void) setreuid(ruid, euid); +	if (pid < 0) { +		debug("open_streams"); +		return (0); +	} +	xdrstdio_create(&xdrargs, fargs, XDR_ENCODE); +	xdrstdio_create(&xdrrslt, frslt, XDR_DECODE); + +	if (!xdr_u_long(&xdrargs, &proc) || !(*xdr_arg)(&xdrargs, arg)) { +		debug("xdr args"); +		success = 0;  +	} +	(void) fclose(fargs); + +	if (success && !(*xdr_rslt)(&xdrrslt, rslt)) { +		debug("xdr rslt"); +		success = 0; +	} + +#ifdef NOTDEF +    /* +     * WARNING! XXX +     * The original code appears first.  wait4 returns only after the process +     * with the requested pid terminates.  The effect of using wait() instead +     * has not been determined. +     */ +	(void) fclose(frslt); +	if (wait4(pid, &status, 0, NULL) < 0 || status.w_retcode != 0) { +		debug("wait4"); +		success = 0; +	} +#endif /* def NOTDEF */ +	if (wait(&status) < 0 || status.w_retcode != 0) { +		debug("wait"); +		success = 0; +	} +	(void)signal(SIGCHLD, osigchild); + +	return (success); +} + diff --git a/lib/librpc/secure_rpc/rpc/key_prot.c b/lib/librpc/secure_rpc/rpc/key_prot.c new file mode 100644 index 000000000000..a93f54312a0e --- /dev/null +++ b/lib/librpc/secure_rpc/rpc/key_prot.c @@ -0,0 +1,165 @@ +#if defined(LIBC_SCCS) && !defined(lint) +static char sccsid[] = 	"@(#)key_prot.c	2.1 88/08/07 4.0 RPCSRC; from 1.4 88/02/08 SMI"; +#endif + +/* + * Copyright (c) 1988 by Sun Microsystems, Inc. + */ +/* + * Sun RPC is a product of Sun Microsystems, Inc. and is provided for + * unrestricted use provided that this legend is included on all tape + * media and as a part of the software program in whole or part.  Users + * may copy or modify Sun RPC without charge, but are not authorized + * to license or distribute it to anyone else except as part of a product or + * program developed by the user. + *  + * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE + * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR + * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. + *  + * Sun RPC is provided with no support and without any obligation on the + * part of Sun Microsystems, Inc. to assist in its use, correction, + * modification or enhancement. + *  + * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE + * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC + * OR ANY PART THEREOF. + *  + * In no event will Sun Microsystems, Inc. be liable for any lost revenue + * or profits or other special, indirect and consequential damages, even if + * Sun has been advised of the possibility of such damages. + *  + * Sun Microsystems, Inc. + * 2550 Garcia Avenue + * Mountain View, California  94043 + */ +#include <rpc/rpc.h> +#include <rpc/key_prot.h> + + +/*  + * Compiled from key_prot.x using rpcgen. + * DO NOT EDIT THIS FILE! + * This is NOT source code! + */ + + +bool_t +xdr_keystatus(xdrs, objp) +	XDR *xdrs; +	keystatus *objp; +{ +	if (!xdr_enum(xdrs, (enum_t *)objp)) { +		return (FALSE); +	} +	return (TRUE); +} + + + + +bool_t +xdr_keybuf(xdrs, objp) +	XDR *xdrs; +	keybuf objp; +{ +	if (!xdr_opaque(xdrs, objp, HEXKEYBYTES)) { +		return (FALSE); +	} +	return (TRUE); +} + + + + +bool_t +xdr_netnamestr(xdrs, objp) +	XDR *xdrs; +	netnamestr *objp; +{ +	if (!xdr_string(xdrs, objp, MAXNETNAMELEN)) { +		return (FALSE); +	} +	return (TRUE); +} + + + + +bool_t +xdr_cryptkeyarg(xdrs, objp) +	XDR *xdrs; +	cryptkeyarg *objp; +{ +	if (!xdr_netnamestr(xdrs, &objp->remotename)) { +		return (FALSE); +	} +	if (!xdr_des_block(xdrs, &objp->deskey)) { +		return (FALSE); +	} +	return (TRUE); +} + + + + +bool_t +xdr_cryptkeyres(xdrs, objp) +	XDR *xdrs; +	cryptkeyres *objp; +{ +	if (!xdr_keystatus(xdrs, &objp->status)) { +		return (FALSE); +	} +	switch (objp->status) { +	case KEY_SUCCESS: +		if (!xdr_des_block(xdrs, &objp->cryptkeyres_u.deskey)) { +			return (FALSE); +		} +		break; +	} +	return (TRUE); +} + + + + +bool_t +xdr_unixcred(xdrs, objp) +	XDR *xdrs; +	unixcred *objp; +{ +	if (!xdr_int(xdrs, &objp->uid)) { +		return (FALSE); +	} +	if (!xdr_int(xdrs, &objp->gid)) { +		return (FALSE); +	} +	if (!xdr_array(xdrs, (char **)&objp->gids.gids_val, (u_int *)&objp->gids.gids_len, MAXGIDS, sizeof(int), xdr_int)) { +		return (FALSE); +	} +	return (TRUE); +} + + + + +bool_t +xdr_getcredres(xdrs, objp) +	XDR *xdrs; +	getcredres *objp; +{ +	if (!xdr_keystatus(xdrs, &objp->status)) { +		return (FALSE); +	} +	switch (objp->status) { +	case KEY_SUCCESS: +		if (!xdr_unixcred(xdrs, &objp->getcredres_u.cred)) { +			return (FALSE); +		} +		break; +	} +	return (TRUE); +} + + diff --git a/lib/librpc/secure_rpc/rpc/key_prot.h b/lib/librpc/secure_rpc/rpc/key_prot.h new file mode 100644 index 000000000000..277e4b832634 --- /dev/null +++ b/lib/librpc/secure_rpc/rpc/key_prot.h @@ -0,0 +1,114 @@ +/*	@(#)key_prot.h	2.1 88/08/07 4.0 RPCSRC; from  1.4 87/03/10 Copyr 1986 Sun Micro */ + +/* + * Copyright (c) 1988 by Sun Microsystems, Inc. + */ +/* + * Sun RPC is a product of Sun Microsystems, Inc. and is provided for + * unrestricted use provided that this legend is included on all tape + * media and as a part of the software program in whole or part.  Users + * may copy or modify Sun RPC without charge, but are not authorized + * to license or distribute it to anyone else except as part of a product or + * program developed by the user. + *  + * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE + * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR + * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. + *  + * Sun RPC is provided with no support and without any obligation on the + * part of Sun Microsystems, Inc. to assist in its use, correction, + * modification or enhancement. + *  + * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE + * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC + * OR ANY PART THEREOF. + *  + * In no event will Sun Microsystems, Inc. be liable for any lost revenue + * or profits or other special, indirect and consequential damages, even if + * Sun has been advised of the possibility of such damages. + *  + * Sun Microsystems, Inc. + * 2550 Garcia Avenue + * Mountain View, California  94043 + */ + + +/*  + * Compiled from key_prot.x using rpcgen. + * DO NOT EDIT THIS FILE! + * This is NOT source code! + */ + +#define KEY_PROG 100029 +#define KEY_VERS 1 +#define KEY_SET 1 +#define KEY_ENCRYPT 2 +#define KEY_DECRYPT 3 +#define KEY_GEN 4 +#define KEY_GETCRED 5 + +#define PROOT 3 +#define HEXMODULUS "d4a0ba0250b6fd2ec626e7efd637df76c716e22d0944b88b" +#define HEXKEYBYTES 48 +#define KEYSIZE 192 +#define KEYBYTES 24 +#define KEYCHECKSUMSIZE 16 + +enum keystatus { +	KEY_SUCCESS = 0, +	KEY_NOSECRET = 1, +	KEY_UNKNOWN = 2, +	KEY_SYSTEMERR = 3, +}; +typedef enum keystatus keystatus; +bool_t xdr_keystatus(); + + +typedef char keybuf[HEXKEYBYTES]; +bool_t xdr_keybuf(); + + +typedef char *netnamestr; +bool_t xdr_netnamestr(); + + +struct cryptkeyarg { +	netnamestr remotename; +	des_block deskey; +}; +typedef struct cryptkeyarg cryptkeyarg; +bool_t xdr_cryptkeyarg(); + + +struct cryptkeyres { +	keystatus status; +	union { +		des_block deskey; +	} cryptkeyres_u; +}; +typedef struct cryptkeyres cryptkeyres; +bool_t xdr_cryptkeyres(); + +#define MAXGIDS 16 + +struct unixcred { +	int uid; +	int gid; +	struct { +		u_int gids_len; +		int *gids_val; +	} gids; +}; +typedef struct unixcred unixcred; +bool_t xdr_unixcred(); + + +struct getcredres { +	keystatus status; +	union { +		unixcred cred; +	} getcredres_u; +}; +typedef struct getcredres getcredres; +bool_t xdr_getcredres(); + diff --git a/lib/librpc/secure_rpc/rpc/key_prot.x b/lib/librpc/secure_rpc/rpc/key_prot.x new file mode 100644 index 000000000000..2f6ebdbcf0ef --- /dev/null +++ b/lib/librpc/secure_rpc/rpc/key_prot.x @@ -0,0 +1,151 @@ +%/*	@(#)key_prot.x	2.1 88/08/07 4.0 RPCSRC; from 1.7 88/02/08 SMI */ +% +%/* +% * Copyright (c) 1988 by Sun Microsystems, Inc. +% */ +% +%/*  +% * Compiled from key_prot.x using rpcgen. +% * DO NOT EDIT THIS FILE! +% * This is NOT source code! +% */ + +/* + * Key server protocol definition + * Copyright (C) 1987 Sun Microsystems, Inc. + * + * The keyserver is a public key storage/encryption/decryption service + * The encryption method used is Diffie-Hellman with 128 bit keys. + * + * The key server is local to each machine, akin to the portmapper. + * Only privileged processes may talk to the key server, so + * user processes must communicate through a privileged dispatcher (such  + * as the kernel or a set-uid-root process). + */ +program KEY_PROG { +	version KEY_VERS { +		/* +		 * This is my secret key. +	 	 * Store it for me. +		 */ +		int  +		KEY_SET(keybuf) = 1;	 +	 +		/* +		 * I want to talk to X. +		 * Encrypt a conversation key for me. +	 	 */ +		cryptkeyres +		KEY_ENCRYPT(cryptkeyarg) = 2;	 + +		/* +		 * X just sent me a message. +		 * Decrypt the conversation key for me. +		 */ +		cryptkeyres +		KEY_DECRYPT(cryptkeyarg) = 3; + +		/* +		 * Generate a secure conversation key for me +		 */ +		des_block  +		KEY_GEN(void) = 4; + +		/* +		 * Get me the uid, gid and group-access-list associated +		 * with this netname (for kernel which cannot use yp) +		 */ +		getcredres +		KEY_GETCRED(netnamestr) = 5; +	} = 1; +} = 100029; + + +/* + * PROOT and MODULUS define the way the Diffie-Hellman key is generated. + * + * MODULUS should be chosen as a prime of the form: MODULUS == 2*p + 1, + * where p is also prime. + * + * PROOT satisfies the following two conditions: + * (1) (PROOT ** 2) % MODULUS != 1 + * (2) (PROOT ** p) % MODULUS != 1 + * + */ + +const PROOT = 3; +const HEXMODULUS = "d4a0ba0250b6fd2ec626e7efd637df76c716e22d0944b88b"; + +const HEXKEYBYTES = 48;		/* HEXKEYBYTES == strlen(HEXMODULUS) */ +const KEYSIZE = 192;		/* KEYSIZE == bit length of key */ +const KEYBYTES = 24;		/* byte length of key */ + +/* + * The first 16 hex digits of the encrypted secret key are used as + * a checksum in the database. + */ +const KEYCHECKSUMSIZE = 16; + +/* + * status of operation + */ +enum keystatus { +	KEY_SUCCESS,	/* no problems */ +	KEY_NOSECRET,	/* no secret key stored */ +	KEY_UNKNOWN,	/* unknown netname */ +	KEY_SYSTEMERR 	/* system error (out of memory, encryption failure) */ +}; + +/* + * The kernel doesn't use keybuf, so we insure that it + * is ifdef'd out in the output files. The proper way to do + * this is to #ifndef KERNEL it here, and have the kernel build + * use rpcgen, but config doesn't understand rpcgen files so + * it is done this way. + */ +#ifndef RPC_SVC +%#ifndef KERNEL +typedef opaque keybuf[HEXKEYBYTES];	/* store key in hex */ +%#endif +#endif + +typedef string netnamestr<MAXNETNAMELEN>; + +/* + * Argument to ENCRYPT or DECRYPT  + */ +struct cryptkeyarg { +	netnamestr remotename; +	des_block deskey; +}; + +/* + * Result of ENCRYPT or DECRYPT + */ +union cryptkeyres switch (keystatus status) { +case KEY_SUCCESS: +	des_block deskey; +default: +	void; +}; + +const MAXGIDS  = 16;	/* max number of gids in gid list */ + +/* + * Unix credential  + */	 +struct unixcred { +	int uid; +	int gid; +	int gids<MAXGIDS>;	 +}; + +/* + * Result returned from GETCRED + */ +union getcredres switch (keystatus status) { +case KEY_SUCCESS: +	unixcred cred; +default: +	void; +}; diff --git a/lib/librpc/secure_rpc/rpc/netname.c b/lib/librpc/secure_rpc/rpc/netname.c new file mode 100644 index 000000000000..21e2491d9a8d --- /dev/null +++ b/lib/librpc/secure_rpc/rpc/netname.c @@ -0,0 +1,239 @@ +#if defined(LIBC_SCCS) && !defined(lint) +static char sccsid[] = 	"@(#)netname.c	2.2 88/08/10 4.0 RPCSRC; from 1.9 88/02/08 SMI"; +#endif +/* + * Sun RPC is a product of Sun Microsystems, Inc. and is provided for + * unrestricted use provided that this legend is included on all tape + * media and as a part of the software program in whole or part.  Users + * may copy or modify Sun RPC without charge, but are not authorized + * to license or distribute it to anyone else except as part of a product or + * program developed by the user. + *  + * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE + * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR + * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. + *  + * Sun RPC is provided with no support and without any obligation on the + * part of Sun Microsystems, Inc. to assist in its use, correction, + * modification or enhancement. + *  + * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE + * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC + * OR ANY PART THEREOF. + *  + * In no event will Sun Microsystems, Inc. be liable for any lost revenue + * or profits or other special, indirect and consequential damages, even if + * Sun has been advised of the possibility of such damages. + *  + * Sun Microsystems, Inc. + * 2550 Garcia Avenue + * Mountain View, California  94043 + */ + +/* + * Copyright (c) 1988 by Sun Microsystems, Inc. + */ + +/* + * netname utility routines + * convert from unix names to network names and vice-versa + * This module is operating system dependent! + * What we define here will work with any unix system that has adopted + * the sun yp domain architecture. + */ +#include <sys/param.h> +#include <rpc/rpc.h> +#include <ctype.h> + +extern char *sprintf(); +extern char *strncpy(); + +static char OPSYS[] = "unix"; +static char NETID[] = "netid.byname";	 + +/* + * Convert network-name into unix credential + */ +netname2user(netname, uidp, gidp, gidlenp, gidlist) +	char netname[MAXNETNAMELEN+1]; +	int *uidp; +	int *gidp; +	int *gidlenp; +	int *gidlist; +{ +	int stat; +	char *val; +	char *p; +	int vallen; +	char *domain; +	int gidlen; + +	stat = yp_get_default_domain(&domain); +	if (stat != 0) { +		return (0); +	} +	stat = yp_match(domain, NETID, netname, strlen(netname), &val, &vallen); +	if (stat != 0) { +		return (0); +	} +	val[vallen] = 0; +	p = val; +	*uidp = atois(&p); +	if (p == NULL || *p++ != ':') { +		free(val); +		return (0); +	} +	*gidp = atois(&p); +	if (p == NULL) { +		free(val); +		return (0); +	} +	gidlen = 0; +	for (gidlen = 0; gidlen < NGROUPS; gidlen++) {	 +		if (*p++ != ',') { +			break; +		} +		gidlist[gidlen] = atois(&p); +		if (p == NULL) { +			free(val); +			return (0); +		} +	} +	*gidlenp = gidlen; +	free(val); +	return (1); +} + +/* + * Convert network-name to hostname + */ +netname2host(netname, hostname, hostlen) +	char netname[MAXNETNAMELEN+1]; +	char *hostname; +	int hostlen; +{ +	int stat; +	char *val; +	int vallen; +	char *domain; + +	stat = yp_get_default_domain(&domain); +	if (stat != 0) { +		return (0); +	} +	stat = yp_match(domain, NETID, netname, strlen(netname), &val, &vallen); +	if (stat != 0) { +		return (0); +	} +	val[vallen] = 0; +	if (*val != '0') { +		free(val); +		return (0); +	}	 +	if (val[1] != ':') { +		free(val); +		return (0); +	} +	(void) strncpy(hostname, val + 2, hostlen); +	free(val); +	return (1); +} + + +/* + * Figure out my fully qualified network name + */ +getnetname(name) +	char name[MAXNETNAMELEN+1]; +{ +	int uid; + +	uid = geteuid();  +	if (uid == 0) { +		return (host2netname(name, (char *) NULL, (char *) NULL)); +	} else { +		return (user2netname(name, uid, (char *) NULL)); +	} +} + + +/* + * Convert unix cred to network-name + */ +user2netname(netname, uid, domain) +	char netname[MAXNETNAMELEN + 1]; +	int uid; +	char *domain; +{ +	char *dfltdom; + +#define MAXIPRINT	(11)	/* max length of printed integer */ + +	if (domain == NULL) { +		if (yp_get_default_domain(&dfltdom) != 0) { +			return (0); +		} +		domain = dfltdom; +	} +	if (strlen(domain) + 1 + MAXIPRINT > MAXNETNAMELEN) { +		return (0); +	} +	(void) sprintf(netname, "%s.%d@%s", OPSYS, uid, domain);	 +	return (1); +} + + +/* + * Convert host to network-name + */ +host2netname(netname, host, domain) +	char netname[MAXNETNAMELEN + 1]; +	char *host; +	char *domain; +{ +	char *dfltdom; +	char hostname[MAXHOSTNAMELEN+1];  + +	if (domain == NULL) { +		if (yp_get_default_domain(&dfltdom) != 0) { +			return (0); +		} +		domain = dfltdom; +	} +	if (host == NULL) { +		(void) gethostname(hostname, sizeof(hostname)); +		host = hostname; +	} +	if (strlen(domain) + 1 + strlen(host) > MAXNETNAMELEN) { +		return (0); +	}  +	(void) sprintf(netname, "%s.%s@%s", OPSYS, host, domain); +	return (1); +} + + +static +atois(str) +	char **str; +{ +	char *p; +	int n; +	int sign; + +	if (**str == '-') { +		sign = -1; +		(*str)++; +	} else { +		sign = 1; +	} +	n = 0; +	for (p = *str; isdigit(*p); p++) { +		n = (10 * n) + (*p - '0'); +	} +	if (p == *str) { +		*str = NULL; +		return (0); +	} +	*str = p;	 +	return (n * sign); +} diff --git a/lib/librpc/secure_rpc/rpc/openchild.c b/lib/librpc/secure_rpc/rpc/openchild.c new file mode 100644 index 000000000000..b30e61515902 --- /dev/null +++ b/lib/librpc/secure_rpc/rpc/openchild.c @@ -0,0 +1,133 @@ +#if defined(LIBC_SCCS) && !defined(lint) +static char sccsid[] = 	"@(#)openchild.c	2.3 88/08/15 4.0 RPCSRC; from 1.7 88/02/08 SMI"; +#endif +/* + * Sun RPC is a product of Sun Microsystems, Inc. and is provided for + * unrestricted use provided that this legend is included on all tape + * media and as a part of the software program in whole or part.  Users + * may copy or modify Sun RPC without charge, but are not authorized + * to license or distribute it to anyone else except as part of a product or + * program developed by the user. + *  + * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE + * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR + * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. + *  + * Sun RPC is provided with no support and without any obligation on the + * part of Sun Microsystems, Inc. to assist in its use, correction, + * modification or enhancement. + *  + * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE + * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC + * OR ANY PART THEREOF. + *  + * In no event will Sun Microsystems, Inc. be liable for any lost revenue + * or profits or other special, indirect and consequential damages, even if + * Sun has been advised of the possibility of such damages. + *  + * Sun Microsystems, Inc. + * 2550 Garcia Avenue + * Mountain View, California  94043 + */ + +/* + * Copyright (c) 1988 by Sun Microsystems, Inc. + */ + +/* + * Open two pipes to a child process, one for reading, one for writing. + * The pipes are accessed by FILE pointers. This is NOT a public + * interface, but for internal use only! + */ +#include <stdio.h> + +extern char *malloc(); +extern char *rindex(); +extern char *sprintf(); + +static char *basename(); +static char SHELL[] = "/bin/sh"; + + +/* + * returns pid, or -1 for failure + */ +_openchild(command, fto, ffrom) +	char *command; +	FILE **fto; +	FILE **ffrom; +{ +	int i; +	int pid; +	int pdto[2]; +	int pdfrom[2]; +	char *com; + +		 +	if (pipe(pdto) < 0) { +		goto error1; +	} +	if (pipe(pdfrom) < 0) { +		goto error2; +	} +	switch (pid = vfork()) { +	case -1: +		goto error3; + +	case 0: +		/*  +		 * child: read from pdto[0], write into pdfrom[1] +		 */ +		(void) close(0);  +		(void) dup(pdto[0]); +		(void) close(1);  +		(void) dup(pdfrom[1]); +		for (i = _rpc_dtablesize() - 1; i >= 3; i--) { +			(void) close(i); +		} +		com = malloc((unsigned) strlen(command) + 6); +		if (com == NULL) { +			_exit(~0); +		}	 +		(void) sprintf(com, "exec %s", command); +		execl(SHELL, basename(SHELL), "-c", com, NULL); +		_exit(~0); +  +	default: +		/* +		 * parent: write into pdto[1], read from pdfrom[0] +		 */ +		*fto = fdopen(pdto[1], "w"); +		(void) close(pdto[0]); +		*ffrom = fdopen(pdfrom[0], "r"); +		(void) close(pdfrom[1]); +		break; +	} +	return (pid); + +	/* +	 * error cleanup and return +	 */ +error3: +	(void) close(pdfrom[0]); +	(void) close(pdfrom[1]); +error2: +	(void) close(pdto[0]); +	(void) close(pdto[1]); +error1: +	return (-1); +} + +static char * +basename(path) +	char *path; +{ +	char *p; + +	p = rindex(path, '/'); +	if (p == NULL) { +		return (path); +	} else { +		return (p + 1); +	} +} diff --git a/lib/librpc/secure_rpc/rpc/publickey.c b/lib/librpc/secure_rpc/rpc/publickey.c new file mode 100644 index 000000000000..d403b63eaf1d --- /dev/null +++ b/lib/librpc/secure_rpc/rpc/publickey.c @@ -0,0 +1,129 @@ +#ifndef lint +static char sccsid[] = 	"@(#)publickey.c	2.3 88/08/15 4.0 RPCSRC"; +#endif +/* + * Sun RPC is a product of Sun Microsystems, Inc. and is provided for + * unrestricted use provided that this legend is included on all tape + * media and as a part of the software program in whole or part.  Users + * may copy or modify Sun RPC without charge, but are not authorized + * to license or distribute it to anyone else except as part of a product or + * program developed by the user. + *  + * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE + * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR + * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. + *  + * Sun RPC is provided with no support and without any obligation on the + * part of Sun Microsystems, Inc. to assist in its use, correction, + * modification or enhancement. + *  + * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE + * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC + * OR ANY PART THEREOF. + *  + * In no event will Sun Microsystems, Inc. be liable for any lost revenue + * or profits or other special, indirect and consequential damages, even if + * Sun has been advised of the possibility of such damages. + *  + * Sun Microsystems, Inc. + * 2550 Garcia Avenue + * Mountain View, California  94043 + */ + +/*  + * Copyright (c) 1988 by Sun Microsystems, Inc. + * @(#) from SUN 1.3 + */ + +/* + * Public key lookup routines + */ +#include <stdio.h> +#include <pwd.h> +#include <rpc/rpc.h> +#include <rpc/key_prot.h> + + +extern char *index(); +extern char *strcpy(); + +static char PKMAP[] = "publickey.byname"; + +/* + * Get somebody's encrypted secret key from the database, using + * the given passwd to decrypt it. + */ +getsecretkey(netname, secretkey, passwd) +	char *netname; +	char *secretkey; +	char *passwd; +{ +	char *domain; +	int len; +	char *lookup; +	int err; +	char *p; + + +	err = yp_get_default_domain(&domain); +	if (err) { +		return(0); +	} +	err = yp_match(domain, PKMAP, netname, strlen(netname), &lookup, &len); +	if (err) { +		return(0); +	} +	lookup[len] = 0; +	p = index(lookup,':'); +	if (p == NULL) { +		free(lookup); +		return(0); +	} +	p++; +	if (!xdecrypt(p, passwd)) { +		free(lookup); +		return(0); +	} +	if (bcmp(p, p + HEXKEYBYTES, KEYCHECKSUMSIZE) != 0) { +		secretkey[0] = 0; +		free(lookup); +		return(1); +	} +	p[HEXKEYBYTES] = 0; +	(void) strcpy(secretkey, p); +	free(lookup); +	return(1); +} + + + +/* + * Get somebody's public key + */ +getpublickey(netname, publickey) +	char *netname; +	char *publickey; +{ +	char *domain; +	int len; +	char *lookup; +	int err; +	char *p; + +	err = yp_get_default_domain(&domain);	 +	if (err) { +		return(0); +	} +	err = yp_match(domain, PKMAP, netname, strlen(netname), &lookup, &len); +	if (err) { +		return(0); +	} +	p = index(lookup, ':'); +	if (p == NULL) { +		free(lookup); +		return(0); +	} +	*p = 0;	 +	(void) strcpy(publickey, lookup); +	return(1); +} diff --git a/lib/librpc/secure_rpc/rpc/rtime.c b/lib/librpc/secure_rpc/rpc/rtime.c new file mode 100644 index 000000000000..725995cb6855 --- /dev/null +++ b/lib/librpc/secure_rpc/rpc/rtime.c @@ -0,0 +1,141 @@ +#if defined(LIBC_SCCS) && !defined(lint) +static char sccsid[] = 	"@(#)rtime.c	2.2 88/08/10 4.0 RPCSRC; from 1.8 88/02/08 SMI"; +#endif +/* + * Sun RPC is a product of Sun Microsystems, Inc. and is provided for + * unrestricted use provided that this legend is included on all tape + * media and as a part of the software program in whole or part.  Users + * may copy or modify Sun RPC without charge, but are not authorized + * to license or distribute it to anyone else except as part of a product or + * program developed by the user. + *  + * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE + * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR + * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. + *  + * Sun RPC is provided with no support and without any obligation on the + * part of Sun Microsystems, Inc. to assist in its use, correction, + * modification or enhancement. + *  + * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE + * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC + * OR ANY PART THEREOF. + *  + * In no event will Sun Microsystems, Inc. be liable for any lost revenue + * or profits or other special, indirect and consequential damages, even if + * Sun has been advised of the possibility of such damages. + *  + * Sun Microsystems, Inc. + * 2550 Garcia Avenue + * Mountain View, California  94043 + */ + +/* + * Copyright (c) 1988 by Sun Microsystems, Inc. + + */ + +/* + * rtime - get time from remote machine + * + * gets time, obtaining value from host + * on the udp/time socket.  Since timeserver returns + * with time of day in seconds since Jan 1, 1900,  must + * subtract seconds before Jan 1, 1970 to get + * what unix uses. + */ +#include <sys/types.h> +#include <sys/socket.h> +#include <sys/time.h> +#include <sys/errno.h> +#include <netinet/in.h> +#include <stdio.h> + +#define NYEARS	(1970 - 1900) +#define TOFFSET (60*60*24*(365*NYEARS + (NYEARS/4))) +extern errno; + +static void do_close(); + +rtime(addrp, timep, timeout) +	struct sockaddr_in *addrp; +	struct timeval *timep; +	struct timeval *timeout; +{ +	int s; +	fd_set readfds; +	int res; +	unsigned long thetime; +	struct sockaddr_in from; +	int fromlen; +	int type; + +	if (timeout == NULL) { +		type = SOCK_STREAM; +	} else { +		type = SOCK_DGRAM; +	} +	s = socket(AF_INET, type, 0); +	if (s < 0) { +		return(-1); +	} +	addrp->sin_family = AF_INET; +	addrp->sin_port = htons(IPPORT_TIMESERVER); +	if (type == SOCK_DGRAM) { +		res = sendto(s, (char *)&thetime, sizeof(thetime), 0,  +			     (struct sockaddr *)addrp, sizeof(*addrp)); +		if (res < 0) { +			do_close(s); +			return(-1);	 +		} +		do { +			FD_ZERO(&readfds); +			FD_SET(s, &readfds); +			res = select(_rpc_dtablesize(), &readfds, (int *)NULL,  +				     (int *)NULL, timeout); +		} while (res < 0 && errno == EINTR); +		if (res <= 0) { +			if (res == 0) { +				errno = ETIMEDOUT; +			} +			do_close(s); +			return(-1);	 +		} +		fromlen = sizeof(from); +		res = recvfrom(s, (char *)&thetime, sizeof(thetime), 0,  +			       (struct sockaddr *)&from, &fromlen); +		do_close(s); +		if (res < 0) { +			return(-1);	 +		} +	} else { +		if (connect(s, (struct sockaddr *)addrp, sizeof(*addrp)) < 0) { +			do_close(s); +			return(-1); +		} +		res = read(s, (char *)&thetime, sizeof(thetime)); +		do_close(s); +		if (res < 0) { +			return(-1); +		} +	} +	if (res != sizeof(thetime)) { +		errno = EIO; +		return(-1);	 +	} +	thetime = ntohl(thetime); +	timep->tv_sec = thetime - TOFFSET; +	timep->tv_usec = 0; +	return(0); +} + +static void +do_close(s) +	int s; +{ +	int save; + +	save = errno; +	(void) close(s); +	errno = save; +} diff --git a/lib/librpc/secure_rpc/rpc/svc_auth.c b/lib/librpc/secure_rpc/rpc/svc_auth.c new file mode 100644 index 000000000000..7ad47cad60a6 --- /dev/null +++ b/lib/librpc/secure_rpc/rpc/svc_auth.c @@ -0,0 +1,116 @@ +/* @(#)svc_auth.c	2.4 88/08/15 4.0 RPCSRC */ +/* + * Sun RPC is a product of Sun Microsystems, Inc. and is provided for + * unrestricted use provided that this legend is included on all tape + * media and as a part of the software program in whole or part.  Users + * may copy or modify Sun RPC without charge, but are not authorized + * to license or distribute it to anyone else except as part of a product or + * program developed by the user. + *  + * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE + * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR + * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. + *  + * Sun RPC is provided with no support and without any obligation on the + * part of Sun Microsystems, Inc. to assist in its use, correction, + * modification or enhancement. + *  + * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE + * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC + * OR ANY PART THEREOF. + *  + * In no event will Sun Microsystems, Inc. be liable for any lost revenue + * or profits or other special, indirect and consequential damages, even if + * Sun has been advised of the possibility of such damages. + *  + * Sun Microsystems, Inc. + * 2550 Garcia Avenue + * Mountain View, California  94043 + */ +#if !defined(lint) && defined(SCCSIDS) +static char sccsid[] = "@(#)svc_auth.c 1.19 87/08/11 Copyr 1984 Sun Micro"; +#endif + +/* + * svc_auth.c, Server-side rpc authenticator interface. + * + * Copyright (C) 1984, Sun Microsystems, Inc. + */ + +#include <rpc/rpc.h> + +/* + * svcauthsw is the bdevsw of server side authentication.  + *  + * Server side authenticators are called from authenticate by + * using the client auth struct flavor field to index into svcauthsw. + * The server auth flavors must implement a routine that looks   + * like:  + *  + *	enum auth_stat + *	flavorx_auth(rqst, msg) + *		register struct svc_req *rqst;  + *		register struct rpc_msg *msg; + * + */ + +enum auth_stat _svcauth_null();		/* no authentication */ +enum auth_stat _svcauth_unix();		/* unix style (uid, gids) */ +enum auth_stat _svcauth_short();	/* short hand unix style */ +enum auth_stat _svcauth_des();		/* des style */ + +static struct { +	enum auth_stat (*authenticator)(); +} svcauthsw[] = { +	_svcauth_null,			/* AUTH_NULL */ +	_svcauth_unix,			/* AUTH_UNIX */ +	_svcauth_short,			/* AUTH_SHORT */ +	_svcauth_des			/* AUTH_DES */ +}; +#define	AUTH_MAX	3		/* HIGHEST AUTH NUMBER */ + + +/* + * The call rpc message, msg has been obtained from the wire.  The msg contains + * the raw form of credentials and verifiers.  authenticate returns AUTH_OK + * if the msg is successfully authenticated.  If AUTH_OK then the routine also + * does the following things: + * set rqst->rq_xprt->verf to the appropriate response verifier; + * sets rqst->rq_client_cred to the "cooked" form of the credentials. + * + * NB: rqst->rq_cxprt->verf must be pre-alloctaed; + * its length is set appropriately. + * + * The caller still owns and is responsible for msg->u.cmb.cred and + * msg->u.cmb.verf.  The authentication system retains ownership of + * rqst->rq_client_cred, the cooked credentials. + * + * There is an assumption that any flavour less than AUTH_NULL is + * invalid. + */ +enum auth_stat +_authenticate(rqst, msg) +	register struct svc_req *rqst; +	struct rpc_msg *msg; +{ +	register int cred_flavor; + +	rqst->rq_cred = msg->rm_call.cb_cred; +	rqst->rq_xprt->xp_verf.oa_flavor = _null_auth.oa_flavor; +	rqst->rq_xprt->xp_verf.oa_length = 0; +	cred_flavor = rqst->rq_cred.oa_flavor; +	if ((cred_flavor <= AUTH_MAX) && (cred_flavor >= AUTH_NULL)) { +		return ((*(svcauthsw[cred_flavor].authenticator))(rqst, msg)); +	} + +	return (AUTH_REJECTEDCRED); +} + +enum auth_stat +_svcauth_null(/*rqst, msg*/) +	/*struct svc_req *rqst; +	struct rpc_msg *msg;*/ +{ + +	return (AUTH_OK); +} diff --git a/lib/librpc/secure_rpc/rpc/svcauth_des.c b/lib/librpc/secure_rpc/rpc/svcauth_des.c new file mode 100644 index 000000000000..0129bef5aac3 --- /dev/null +++ b/lib/librpc/secure_rpc/rpc/svcauth_des.c @@ -0,0 +1,519 @@ +#if defined(LIBC_SCCS) && !defined(lint) +static char sccsid[] = 	"@(#)svcauth_des.c	2.3 89/07/11 4.0 RPCSRC; from 1.15 88/02/08 SMI"; +#endif + +/* + * Copyright (c) 1988 by Sun Microsystems, Inc. + */ + +/* + * Sun RPC is a product of Sun Microsystems, Inc. and is provided for + * unrestricted use provided that this legend is included on all tape + * media and as a part of the software program in whole or part.  Users + * may copy or modify Sun RPC without charge, but are not authorized + * to license or distribute it to anyone else except as part of a product or + * program developed by the user. + *  + * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE + * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR + * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. + *  + * Sun RPC is provided with no support and without any obligation on the + * part of Sun Microsystems, Inc. to assist in its use, correction, + * modification or enhancement. + * + * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE + * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC + * OR ANY PART THEREOF. + * + * In no event will Sun Microsystems, Inc. be liable for any lost revenue + * or profits or other special, indirect and consequential damages, even if + * Sun has been advised of the possibility of such damages. + * + * Sun Microsystems, Inc. + * 2550 Garcia Avenue + * Mountain View, California  94043 + */ + +/* + * svcauth_des.c, server-side des authentication + * + * We insure for the service the following: + * (1) The timestamp microseconds do not exceed 1 million. + * (2) The timestamp plus the window is less than the current time. + * (3) The timestamp is not less than the one previously + *     seen in the current session. + * + * It is up to the server to determine if the window size is + * too small . + * + */ + +#include <des_crypt.h> +#include <sys/param.h> +#include <netinet/in.h> +#include <rpc/types.h> +#include <rpc/xdr.h> +#include <rpc/auth.h> +#include <rpc/auth_des.h> +#include <rpc/svc_auth.h> +#include <rpc/svc.h> +#include <rpc/rpc_msg.h> + + +#define debug(msg)	 /*printf("svcauth_des: %s\n", msg)*/  + +extern char *strcpy(); + +#define USEC_PER_SEC ((u_long) 1000000L) +#define BEFORE(t1, t2) timercmp(t1, t2, <) + +/* + * LRU cache of conversation keys and some other useful items. + */ +#define AUTHDES_CACHESZ 64 +struct cache_entry { +	des_block key;		/* conversation key */ +	char *rname;		/* client's name */ +	u_int window;		/* credential lifetime window */ +	struct timeval laststamp;	/* detect replays of creds */ +	char *localcred;	/* generic local credential */ +}; +static struct cache_entry *authdes_cache/* [AUTHDES_CACHESZ] */; +static short *authdes_lru/* [AUTHDES_CACHESZ] */; + +static void cache_init();	/* initialize the cache */ +static short cache_spot();	/* find an entry in the cache */ +static void cache_ref(/*short sid*/);	/* note that sid was ref'd */ + +static void invalidate();	/* invalidate entry in cache */ + +/* + * cache statistics  + */ +struct { +	u_long ncachehits;	/* times cache hit, and is not replay */ +	u_long ncachereplays;	/* times cache hit, and is replay */ +	u_long ncachemisses;	/* times cache missed */ +} svcauthdes_stats; + +/* + * Service side authenticator for AUTH_DES + */ +enum auth_stat +_svcauth_des(rqst, msg) +	register struct svc_req *rqst; +	register struct rpc_msg *msg; +{ + +	register long *ixdr; +	des_block cryptbuf[2]; +	register struct authdes_cred *cred; +	struct authdes_verf verf; +	int status; +	register struct cache_entry *entry; +	short sid; +	des_block *sessionkey; +	des_block ivec; +	u_int window; +	struct timeval timestamp; +	u_long namelen; +	struct area { +		struct authdes_cred area_cred; +		char area_netname[MAXNETNAMELEN+1]; +	} *area; + +	if (authdes_cache == NULL) { +		cache_init(); +	} + +	area = (struct area *)rqst->rq_clntcred; +	cred = (struct authdes_cred *)&area->area_cred; + +	/* +	 * Get the credential +	 */ +	ixdr = (long *)msg->rm_call.cb_cred.oa_base; +	cred->adc_namekind = IXDR_GET_ENUM(ixdr, enum authdes_namekind); +	switch (cred->adc_namekind) { +	case ADN_FULLNAME: +		namelen = IXDR_GET_U_LONG(ixdr); +		if (namelen > MAXNETNAMELEN) { +			return (AUTH_BADCRED); +		} +		cred->adc_fullname.name = area->area_netname; +		bcopy((char *)ixdr, cred->adc_fullname.name,  +			(u_int)namelen); +		cred->adc_fullname.name[namelen] = 0; +		ixdr += (RNDUP(namelen) / BYTES_PER_XDR_UNIT); +		cred->adc_fullname.key.key.high = (u_long)*ixdr++; +		cred->adc_fullname.key.key.low = (u_long)*ixdr++; +		cred->adc_fullname.window = (u_long)*ixdr++; +		break; +	case ADN_NICKNAME: +		cred->adc_nickname = (u_long)*ixdr++; +		break; +	default: +		return (AUTH_BADCRED);	 +	} + +	/* +	 * Get the verifier +	 */ +	ixdr = (long *)msg->rm_call.cb_verf.oa_base; +	verf.adv_xtimestamp.key.high = (u_long)*ixdr++; +	verf.adv_xtimestamp.key.low =  (u_long)*ixdr++; +	verf.adv_int_u = (u_long)*ixdr++; + + +	/* +	 * Get the conversation key + 	 */ +	if (cred->adc_namekind == ADN_FULLNAME) { +		sessionkey = &cred->adc_fullname.key; +		if (key_decryptsession(cred->adc_fullname.name,  +				       sessionkey) < 0) { +			debug("decryptsessionkey"); +			return (AUTH_BADCRED); /* key not found */ +		} +	} else { /* ADN_NICKNAME */	 +		sid = (short)cred->adc_nickname; +		if (sid >= AUTHDES_CACHESZ) { +			debug("bad nickname"); +			return (AUTH_BADCRED);	/* garbled credential */ +		} +		sessionkey = &authdes_cache[sid].key; +	} + + +	/* +	 * Decrypt the timestamp +	 */ +	cryptbuf[0] = verf.adv_xtimestamp;  +	if (cred->adc_namekind == ADN_FULLNAME) { +		cryptbuf[1].key.high = cred->adc_fullname.window; +		cryptbuf[1].key.low = verf.adv_winverf; +		ivec.key.high = ivec.key.low = 0;	 +		status = cbc_crypt((char *)sessionkey, (char *)cryptbuf, +			2*sizeof(des_block), DES_DECRYPT | DES_HW,  +			(char *)&ivec); +	} else { +		status = ecb_crypt((char *)sessionkey, (char *)cryptbuf, +			sizeof(des_block), DES_DECRYPT | DES_HW); +	} +	if (DES_FAILED(status)) { +		debug("decryption failure"); +		return (AUTH_FAILED);	/* system error */ +	} + +	/* +	 * XDR the decrypted timestamp +	 */ +	ixdr = (long *)cryptbuf; +	timestamp.tv_sec = IXDR_GET_LONG(ixdr); +	timestamp.tv_usec = IXDR_GET_LONG(ixdr); + +	/* + 	 * Check for valid credentials and verifiers. +	 * They could be invalid because the key was flushed +	 * out of the cache, and so a new session should begin. +	 * Be sure and send AUTH_REJECTED{CRED, VERF} if this is the case. +	 */ +	{ +		struct timeval current; +		int nick; +		int winverf; + +		if (cred->adc_namekind == ADN_FULLNAME) { +			window = IXDR_GET_U_LONG(ixdr); +			winverf = IXDR_GET_U_LONG(ixdr); +			if (winverf != window - 1) { +				debug("window verifier mismatch"); +				return (AUTH_BADCRED);	/* garbled credential */ +			} +			sid = cache_spot(sessionkey, cred->adc_fullname.name,  +			    ×tamp); +			if (sid < 0) { +				debug("replayed credential"); +				return (AUTH_REJECTEDCRED);	/* replay */ +			} +			nick = 0; +		} else {	/* ADN_NICKNAME */ +			window = authdes_cache[sid].window; +			nick = 1; +		} + +		if ((u_long)timestamp.tv_usec >= USEC_PER_SEC) { +			debug("invalid usecs"); +			/* cached out (bad key), or garbled verifier */ +			return (nick ? AUTH_REJECTEDVERF : AUTH_BADVERF); +		} +		if (nick && BEFORE(×tamp,  +				   &authdes_cache[sid].laststamp)) { +			debug("timestamp before last seen"); +			return (AUTH_REJECTEDVERF);	/* replay */ +		} +		(void) gettimeofday(¤t, (struct timezone *)NULL); +		current.tv_sec -= window;	/* allow for expiration */ +		if (!BEFORE(¤t, ×tamp)) { +			debug("timestamp expired"); +			/* replay, or garbled credential */ +			return (nick ? AUTH_REJECTEDVERF : AUTH_BADCRED); +		} +	} + +	/* +	 * Set up the reply verifier +	 */ +	verf.adv_nickname = (u_long)sid; + +	/* +	 * xdr the timestamp before encrypting +	 */ +	ixdr = (long *)cryptbuf; +	IXDR_PUT_LONG(ixdr, timestamp.tv_sec - 1); +	IXDR_PUT_LONG(ixdr, timestamp.tv_usec); + +	/*	  +	 * encrypt the timestamp +	 */ +	status = ecb_crypt((char *)sessionkey, (char *)cryptbuf, +	    sizeof(des_block), DES_ENCRYPT | DES_HW); +	if (DES_FAILED(status)) { +		debug("encryption failure"); +		return (AUTH_FAILED);	/* system error */ +	} +	verf.adv_xtimestamp = cryptbuf[0]; + +	/* +	 * Serialize the reply verifier, and update rqst +	 */ +	ixdr = (long *)msg->rm_call.cb_verf.oa_base; +	*ixdr++ = (long)verf.adv_xtimestamp.key.high; +	*ixdr++ = (long)verf.adv_xtimestamp.key.low; +	*ixdr++ = (long)verf.adv_int_u; + +	rqst->rq_xprt->xp_verf.oa_flavor = AUTH_DES; +	rqst->rq_xprt->xp_verf.oa_base = msg->rm_call.cb_verf.oa_base; +	rqst->rq_xprt->xp_verf.oa_length =  +		(char *)ixdr - msg->rm_call.cb_verf.oa_base; + +	/* +	 * We succeeded, commit the data to the cache now and +	 * finish cooking the credential. +	 */ +	entry = &authdes_cache[sid]; +	entry->laststamp = timestamp; +	cache_ref(sid); +	if (cred->adc_namekind == ADN_FULLNAME) { +		cred->adc_fullname.window = window; +		cred->adc_nickname = (u_long)sid;	/* save nickname */ +		if (entry->rname != NULL) { +			mem_free(entry->rname, strlen(entry->rname) + 1); +		} +		entry->rname = mem_alloc((u_int)strlen(cred->adc_fullname.name) +					 + 1); +		if (entry->rname != NULL) { +			(void) strcpy(entry->rname, cred->adc_fullname.name); +		} else { +			debug("out of memory"); +		} +		entry->key = *sessionkey; +		entry->window = window; +		invalidate(entry->localcred); /* mark any cached cred invalid */ +	} else { /* ADN_NICKNAME */ +		/* +		 * nicknames are cooked into fullnames +		 */	 +		cred->adc_namekind = ADN_FULLNAME; +		cred->adc_fullname.name = entry->rname; +		cred->adc_fullname.key = entry->key; +		cred->adc_fullname.window = entry->window; +	} +	return (AUTH_OK);	/* we made it!*/ +} + + +/* + * Initialize the cache + */ +static void +cache_init() +{ +	register int i; + +	authdes_cache = (struct cache_entry *) +		mem_alloc(sizeof(struct cache_entry) * AUTHDES_CACHESZ);	 +	bzero((char *)authdes_cache,  +		sizeof(struct cache_entry) * AUTHDES_CACHESZ); + +	authdes_lru = (short *)mem_alloc(sizeof(short) * AUTHDES_CACHESZ); +	/* +	 * Initialize the lru list +	 */ +	for (i = 0; i < AUTHDES_CACHESZ; i++) { +		authdes_lru[i] = i; +	} +} + + +/* + * Find the lru victim + */ +static short +cache_victim() +{ +	return (authdes_lru[AUTHDES_CACHESZ-1]); +} + +/* + * Note that sid was referenced + */ +static void +cache_ref(sid) +	register short sid; +{ +	register int i; +	register short curr; +	register short prev; + +	prev = authdes_lru[0]; +	authdes_lru[0] = sid; +	for (i = 1; prev != sid; i++) { +		curr = authdes_lru[i]; +		authdes_lru[i] = prev; +		prev = curr; +	} +} + + +/* + * Find a spot in the cache for a credential containing + * the items given.  Return -1 if a replay is detected, otherwise + * return the spot in the cache. + */ +static short +cache_spot(key, name, timestamp) +	register des_block *key; +	char *name; +	struct timeval *timestamp; +{ +	register struct cache_entry *cp; +	register int i; +	register u_long hi; + +	hi = key->key.high; +	for (cp = authdes_cache, i = 0; i < AUTHDES_CACHESZ; i++, cp++) { +		if (cp->key.key.high == hi &&  +		    cp->key.key.low == key->key.low && +		    cp->rname != NULL && +		    bcmp(cp->rname, name, strlen(name) + 1) == 0) { +			if (BEFORE(timestamp, &cp->laststamp)) { +				svcauthdes_stats.ncachereplays++; +				return (-1); /* replay */ +			} +			svcauthdes_stats.ncachehits++; +			return (i);	/* refresh */ +		} +	} +	svcauthdes_stats.ncachemisses++; +	return (cache_victim());	/* new credential */ +} + + +#if (defined(sun) || defined(vax)) +/* + * Local credential handling stuff. + * NOTE: bsd unix dependent. + * Other operating systems should put something else here. + */ +#define UNKNOWN 	-2	/* grouplen, if cached cred is unknown user */ +#define INVALID		-1 	/* grouplen, if cache entry is invalid */ + +struct bsdcred { +	short uid;		/* cached uid */ +	short gid;		/* cached gid */ +	short grouplen;	/* length of cached groups */ +	short groups[NGROUPS];	/* cached groups */ +}; + +/* + * Map a des credential into a unix cred. + * We cache the credential here so the application does + * not have to make an rpc call every time to interpret + * the credential. + */ +authdes_getucred(adc, uid, gid, grouplen, groups) +	struct authdes_cred *adc; +	short *uid; +	short *gid; +	short *grouplen; +	register int *groups; +{ +	unsigned sid; +	register int i; +	int i_uid;	 +	int i_gid; +	int i_grouplen; +	struct bsdcred *cred; + +	sid = adc->adc_nickname; +	if (sid >= AUTHDES_CACHESZ) { +		debug("invalid nickname"); +		return (0); +	} +	cred = (struct bsdcred *)authdes_cache[sid].localcred; +	if (cred == NULL) { +		cred = (struct bsdcred *)mem_alloc(sizeof(struct bsdcred)); +		authdes_cache[sid].localcred = (char *)cred; +		cred->grouplen = INVALID; +	} +	if (cred->grouplen == INVALID) { +		/* +		 * not in cache: lookup +		 */ +		if (!netname2user(adc->adc_fullname.name, &i_uid, &i_gid,  +			&i_grouplen, groups)) +		{ +			debug("unknown netname"); +			cred->grouplen = UNKNOWN;	/* mark as lookup up, but not found */ +			return (0); +		} +		debug("missed ucred cache"); +		*uid = cred->uid = i_uid; +		*gid = cred->gid = i_gid; +		*grouplen = cred->grouplen = i_grouplen; +		for (i = i_grouplen - 1; i >= 0; i--) { +			cred->groups[i] = groups[i]; /* int to short */ +		} +		return (1); +	} else if (cred->grouplen == UNKNOWN) { +		/* +		 * Already lookup up, but no match found +		 */	 +		return (0); +	} + +	/* +	 * cached credentials +	 */ +	*uid = cred->uid; +	*gid = cred->gid; +	*grouplen = cred->grouplen; +	for (i = cred->grouplen - 1; i >= 0; i--) { +		groups[i] = cred->groups[i];	/* short to int */ +	} +	return (1); +} + +static void +invalidate(cred) +	char *cred; +{ +	if (cred == NULL) { +		return; +	} +	((struct bsdcred *)cred)->grouplen = INVALID; +} +#endif + diff --git a/lib/librpc/secure_rpc/rpc/xcrypt.c b/lib/librpc/secure_rpc/rpc/xcrypt.c new file mode 100644 index 000000000000..215fda651479 --- /dev/null +++ b/lib/librpc/secure_rpc/rpc/xcrypt.c @@ -0,0 +1,183 @@ +#ifndef lint +static char sccsid[] = "@(#)xcrypt.c	2.2 88/08/10 4.0 RPCSRC"; +#endif +/* + * Sun RPC is a product of Sun Microsystems, Inc. and is provided for + * unrestricted use provided that this legend is included on all tape + * media and as a part of the software program in whole or part.  Users + * may copy or modify Sun RPC without charge, but are not authorized + * to license or distribute it to anyone else except as part of a product or + * program developed by the user. + *  + * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE + * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR + * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. + *  + * Sun RPC is provided with no support and without any obligation on the + * part of Sun Microsystems, Inc. to assist in its use, correction, + * modification or enhancement. + *  + * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE + * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC + * OR ANY PART THEREOF. + *  + * In no event will Sun Microsystems, Inc. be liable for any lost revenue + * or profits or other special, indirect and consequential damages, even if + * Sun has been advised of the possibility of such damages. + *  + * Sun Microsystems, Inc. + * 2550 Garcia Avenue + * Mountain View, California  94043 + */ +/* + * Hex encryption/decryption and utility routines + * + * Copyright (C) 1986, Sun Microsystems, Inc.  + */ + +#include <stdio.h> +#include <des_crypt.h> + +extern char *malloc(); + +extern char hex[];	/* forward */ +static char hexval(); + +/* + * Encrypt a secret key given passwd + * The secret key is passed and returned in hex notation. + * Its length must be a multiple of 16 hex digits (64 bits). + */ +xencrypt(secret, passwd) +	char *secret; +	char *passwd; +{ +	char key[8]; +	char ivec[8]; +	char *buf; +	int err; +	int len; + +	len = strlen(secret) / 2; +	buf = malloc((unsigned)len); + +	hex2bin(len, secret, buf); +	passwd2des(passwd, key); +	bzero(ivec, 8); + +	err = cbc_crypt(key, buf, len, DES_ENCRYPT | DES_HW, ivec); +	if (DES_FAILED(err)) {	 +		free(buf); +		return (0); +	} +	bin2hex(len, (unsigned char *) buf, secret); +	free(buf); +	return (1); +} + +/* + * Decrypt secret key using passwd + * The secret key is passed and returned in hex notation. + * Once again, the length is a multiple of 16 hex digits + */ +xdecrypt(secret, passwd) +	char *secret; +	char *passwd; +{ +	char key[8]; +	char ivec[8]; +	char *buf; +	int err; +	int len; + +	len = strlen(secret) / 2; +	buf = malloc((unsigned)len); + +	hex2bin(len, secret, buf); +	passwd2des(passwd, key);	 +	bzero(ivec, 8); + +	err = cbc_crypt(key, buf, len, DES_DECRYPT | DES_HW, ivec); +	if (DES_FAILED(err)) { +		free(buf); +		return (0); +	} +	bin2hex(len, (unsigned char *) buf, secret); +	free(buf); +	return (1); +} + + +/* + * Turn password into DES key + */ +passwd2des(pw, key) +	char *pw; +	char *key; +{ +	int i; + +	bzero(key, 8); +	for (i = 0; *pw; i = (i+1)%8) { +		key[i] ^= *pw++ << 1; +	} +	des_setparity(key); +} + + + +/* + * Hex to binary conversion + */ +static +hex2bin(len, hexnum, binnum) +	int len; +	char *hexnum; +	char *binnum; +{ +	int i; + +	for (i = 0; i < len; i++) { +		*binnum++ = 16 * hexval(hexnum[2*i]) + hexval(hexnum[2*i+1]);	 +	} +} + +/* + * Binary to hex conversion + */ +static +bin2hex(len, binnum, hexnum) +	int len; +	unsigned char *binnum; +	char *hexnum; +{ +	int i; +	unsigned val; + +	for (i = 0; i < len; i++) { +		val = binnum[i]; +		hexnum[i*2] = hex[val >> 4]; +		hexnum[i*2+1] = hex[val & 0xf]; +	} +	hexnum[len*2] = 0; +} + +static char hex[16] = { +	'0', '1', '2', '3', '4', '5', '6', '7', +	'8', '9', 'a', 'b', 'c', 'd', 'e', 'f', +}; + +static char +hexval(c) +	char c; +{ +	if (c >= '0' && c <= '9') { +		return (c - '0'); +	} else if (c >= 'a' && c <= 'z') { +		return (c - 'a' + 10); +	} else if (c >= 'A' && c <= 'Z') { +		return (c - 'A' + 10); +	} else { +		return (-1); +	} +} diff --git a/lib/libterm/TEST/tc1.c b/lib/libterm/TEST/tc1.c new file mode 100644 index 000000000000..fd0870adc679 --- /dev/null +++ b/lib/libterm/TEST/tc1.c @@ -0,0 +1,63 @@ +/*- + * Copyright (c) 1983, 1993 + *	The 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 copyright[] = +"@(#) Copyright (c) 1983, 1993\n\ +	The Regents of the University of California.  All rights reserved.\n"; +#endif /* not lint */ + +#ifndef lint +static char sccsid[] = "@(#)tc1.c	8.1 (Berkeley) 6/4/93"; +#endif /* not lint */ + +/* + * tc1 [term] + * dummy program to test termlib. + * gets entry, counts it, and prints it. + */ +#include <stdio.h> +char buf[1024]; +char *getenv(); + +main(argc, argv) char **argv; { +	char *p; +	int rc; + +	if (argc < 2) +		p = getenv("TERM"); +	else +		p = argv[1]; +	rc = tgetent(buf,p); +	printf("tgetent returns %d, len=%d, text=\n'%s'\n",rc,strlen(buf),buf); +} diff --git a/lib/libterm/TEST/tc2.c b/lib/libterm/TEST/tc2.c new file mode 100644 index 000000000000..1db9d0027e5d --- /dev/null +++ b/lib/libterm/TEST/tc2.c @@ -0,0 +1,90 @@ +/*- + * Copyright (c) 1983, 1993 + *	The 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 copyright[] = +"@(#) Copyright (c) 1983, 1993\n\ +	The Regents of the University of California.  All rights reserved.\n"; +#endif /* not lint */ + +#ifndef lint +static char sccsid[] = "@(#)tc2.c	8.1 (Berkeley) 6/4/93"; +#endif /* not lint */ + +/* + * tc2 [term] + * Dummy program to test out termlib. + * Commands are "tcc\n" where t is type (s for string, f for flag, + * or n for number) and cc is the name of the capability. + */ +#include <stdio.h> +char buf[1024]; +char *getenv(), *tgetstr(); + +main(argc, argv) char **argv; { +	char *p, *q; +	int rc; +	char b[3], c; +	char area[200]; + +	if (argc < 2) +		p = getenv("TERM"); +	else +		p = argv[1]; +	rc = tgetent(buf,p); +	for (;;) { +		c = getchar(); +		if (c < 0) +			exit(0); +		b[0] = getchar(); +		if (b[0] < ' ') +			exit(0); +		b[1] = getchar(); +		b[2] = 0; +		getchar(); +		switch(c) { +			case 'f': +				printf("%s: %d\n",b,tgetflag(b)); +				break; +			case 'n': +				printf("%s: %d\n",b,tgetnum(b)); +				break; +			case 's': +				q = area; +				printf("%s: %s\n",b,tgetstr(b,&q)); +				break; +			default: +				exit(0); +		} +	} +} diff --git a/lib/libterm/TEST/tc3.c b/lib/libterm/TEST/tc3.c new file mode 100644 index 000000000000..3935e10d18eb --- /dev/null +++ b/lib/libterm/TEST/tc3.c @@ -0,0 +1,112 @@ +/*- + * Copyright (c) 1983, 1993 + *	The 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 copyright[] = +"@(#) Copyright (c) 1983, 1993\n\ +	The Regents of the University of California.  All rights reserved.\n"; +#endif /* not lint */ + +#ifndef lint +static char sccsid[] = "@(#)tc3.c	8.1 (Berkeley) 6/4/93"; +#endif /* not lint */ + +/* + * tc3 [term] + * Dummy program to test out termlib.  Input two numbers (row and col) + * and it prints out the tgoto string generated. + */ +#include <stdio.h> +char buf[1024]; +char *getenv(), *tgetstr(); +char *rdchar(); +char *tgoto(); +char *CM; +char cmbuff[30]; +char *x; +char *UP; +char *tgout; + +main(argc, argv) char **argv; { +	char *p; +	int rc; +	int row, col; + +	if (argc < 2) +		p = getenv("TERM"); +	else +		p = argv[1]; +	rc = tgetent(buf,p); +	x = cmbuff; +	UP = tgetstr("up", &x); +	printf("UP = %x = ", UP); pr(UP); printf("\n"); +	if (UP && *UP==0) +		UP = 0; +	CM = tgetstr("cm", &x); +	printf("CM = "); pr(CM); printf("\n"); +	for (;;) { +		if (scanf("%d %d", &row, &col) < 2) +			exit(0); +		tgout = tgoto(CM, col, row); +		pr(tgout); +		printf("\n"); +	} +} + +pr(p) +register char *p; +{ +	for (; *p; p++) +		printf("%s", rdchar(*p)); +} + +/* + * rdchar() returns a readable representation of an ASCII character + * using ^ for control, ' for meta. + */ +#include <ctype.h> +char *rdchar(c) +char c; +{ +	static char ret[4]; +	register char *p = ret; + +	if ((c&0377) > 0177) +		*p++ = '\''; +	c &= 0177; +	if (!isprint(c)) +		*p++ = '^'; +	*p++ = (isprint(c) ?  c  : c^0100); +	*p = 0; +	return (ret); +} diff --git a/lib/libterm/pathnames.h b/lib/libterm/pathnames.h new file mode 100644 index 000000000000..db3ccf74f21c --- /dev/null +++ b/lib/libterm/pathnames.h @@ -0,0 +1,36 @@ +/* + * Copyright (c) 1989, 1993 + *	The 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. + * + *	@(#)pathnames.h	8.1 (Berkeley) 6/4/93 + */ + +#define	_PATH_DEF	".termcap /usr/share/misc/termcap" diff --git a/lib/libterm/termcap.3 b/lib/libterm/termcap.3 new file mode 100644 index 000000000000..08173cda342b --- /dev/null +++ b/lib/libterm/termcap.3 @@ -0,0 +1,254 @@ +.\" Copyright (c) 1980, 1991, 1993 +.\"	The 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. +.\" +.\"     @(#)termcap.3	8.2 (Berkeley) 12/11/93 +.\" +.Dd December 11, 1993 +.Dt TERMCAP 3 +.Os BSD 4 +.Sh NAME +.Nm tgetent , +.Nm tgetnum , +.Nm tgetflag , +.Nm tgetstr , +.Nm tgoto , +.Nm tputs +.Nd terminal independent operation routines +.Sh SYNOPSIS +.Vt char PC; +.Vt char *BC; +.Vt char *UP; +.Vt short ospeed; +.Fn tgetent "char *bp" "char *name" +.Fn tgetnum "char *id" +.Fn tgetflag "char *id" +.Ft char * +.Fn tgetstr "char *id" "char **area" +.Ft char * +.Fn tgoto "char *cm" destcol destline +.Fn tputs "register char *cp" "int affcnt" "int (*outc)()" +.Sh DESCRIPTION +These functions extract and use capabilities from a terminal capability data +base, usually +.Pa /usr/share/misc/termcap , +the format of which is described in +.Xr termcap 5 . +These are low level routines; +see +.Xr curses 3 +for a higher level package. +.Pp +The +.Fn tgetent +function +extracts the entry for terminal +.Fa name +into the buffer at +.Fa bp . +The +.Fa bp +argument +should be a character buffer of size +1024 and must be retained through all subsequent calls to +.Fn tgetnum , +.Fn tgetflag , +and +.Fn tgetstr . +The +.Fn tgetent +function +returns \-1 if none of the +.Nm termcap +data base files could be opened, +0 if the terminal name given does not have an entry, +and 1 if all goes well. +It will look in the environment for a +.Ev TERMCAP +variable. +If found, and the value does not begin with a slash, +and the terminal type +.Fa name +is the same as the environment string +.Ev TERM , +the +.Ev TERMCAP +string is used instead of reading a +.Nm termcap +file. +If it does begin with a slash, the string is used as a path name +of the +.Nm termcap +file to search. +If +.Ev TERMCAP +does not begin with a slash and +.Fa name +is different from +.Ev TERM , +.Fn tgetent +searches the files +.Pa $HOME/.termcap +and +.Pa /usr/share/misc/termcap , +in that order, unless the environment variable +.Ev TERMPATH +exists, +in which case it specifies a list of file pathnames +(separated by spaces or colons) to be searched instead. +Whenever multiple files are searched and a +.Sy tc +field occurs in the requested entry, the entry it names must be found +in the same file or one of the succeeding files. +This can speed up entry into programs that call +.Fn tgetent , +as well as help debug new terminal descriptions +or make one for your terminal if you can't write the file +.Pa /usr/share/misc/termcap . +.Pp +The +.Fn tgetnum +function +gets the numeric value of capability +.Fa id , +returning \-1 if it is not given for the terminal. +The +.Fn tgetflag +function +returns 1 if the specified capability is present in +the terminal's entry, 0 if it is not. +The +.Fn tgetstr +function +returns the string value of the capability +.Fa id , +places it in the buffer at +.Fa area , +and advances the +.Fa area +pointer. +It decodes the abbreviations for this field described in +.Xr termcap 5 , +except for cursor addressing and padding information. +The +.Fn tgetstr +function +returns +.Dv NULL +if the capability was not found. +.Pp +The +.Fn tgoto +function +returns a cursor addressing string decoded from +.Fa cm +to go to column +.Fa destcol +in line +.Fa destline . +It uses the external variables +.Va UP +(from the +.Sy up +capability) +and +.Va BC +(if +.Sy bc +is given rather than +.Sy bs ) +if necessary to avoid placing +.Sy \en , +.Sy ^D +or +.Sy ^@ +in +the returned string. +(Programs which call +.Fn tgoto +should be sure to turn off the +.Dv XTABS +bit(s), +since +.Fn tgoto +may now output a tab. +Note that programs using termcap should in general turn off +.Dv XTABS +anyway since some terminals use control-I for other functions, +such as nondestructive space.) +If a +.Sy % +sequence is given which is not understood, then +.Fn tgoto +returns +.Pq Dv OOPS . +.Pp +The +.Fn tputs +function +decodes the leading padding information of the string +.Fa cp ; +.Fa affcnt +gives the number of lines affected by the operation, or 1 if this is +not applicable, +.Fa outc +is a routine which is called with each character in turn. +The external variable +.Va ospeed +should contain the output speed of the terminal as encoded by +.Xr stty 3 . +The external variable +.Va PC +should contain a pad character to be used (from the +.SY pc +capability) +if a null +.Pq Sy ^@ +is inappropriate. +.Sh FILES +.Bl -tag -width /usr/share/misc/termcap -compact +.It Pa /usr/lib/libtermcap.a +.Fl l Ar ltermcap +library (also known as +.Fl l Ar ltermlib ) +.It Pa /usr/share/misc/termcap +standard terminal capability data base +.It Pa $HOME/.termcap +user's terminal capability data base +.El +.Sh SEE ALSO +.Xr ex 1 , +.Xr curses 3 , +.Xr termcap 5 +.Sh HISTORY +The +.Nm +functions appeared in  +.Bx 4.0 . diff --git a/lib/libterm/termcap.c b/lib/libterm/termcap.c new file mode 100644 index 000000000000..708ccfaa5d80 --- /dev/null +++ b/lib/libterm/termcap.c @@ -0,0 +1,208 @@ +/* + * Copyright (c) 1980, 1993 + *	The 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 sccsid[] = "@(#)termcap.c	8.1 (Berkeley) 6/4/93"; +#endif /* not lint */ + +#define	PBUFSIZ		512	/* max length of filename path */ +#define	PVECSIZ		32	/* max number of names in path */ + +#include <stdio.h> +#include <ctype.h> +#include <stdlib.h> +#include <string.h> +#include "pathnames.h" + +/* + * termcap - routines for dealing with the terminal capability data base + * + * BUG:		Should use a "last" pointer in tbuf, so that searching + *		for capabilities alphabetically would not be a n**2/2 + *		process when large numbers of capabilities are given. + * Note:	If we add a last pointer now we will screw up the + *		tc capability. We really should compile termcap. + * + * Essentially all the work here is scanning and decoding escapes + * in string capabilities.  We don't use stdio because the editor + * doesn't, and because living w/o it is not hard. + */ + +static	char *tbuf;	/* termcap buffer */ + +/* + * Get an entry for terminal name in buffer bp from the termcap file. + */ +int +tgetent(bp, name) +	char *bp, *name; +{ +	register char *p; +	register char *cp; +	char  *dummy; +	char **fname; +	char  *home; +	int    i; +	char   pathbuf[PBUFSIZ];	/* holds raw path of filenames */ +	char  *pathvec[PVECSIZ];	/* to point to names in pathbuf */ +	char **pvec;			/* holds usable tail of path vector */ +	char  *termpath; + +	fname = pathvec; +	pvec = pathvec; +	tbuf = bp; +	p = pathbuf; +	cp = getenv("TERMCAP"); +	/* +	 * TERMCAP can have one of two things in it. It can be the +	 * name of a file to use instead of /etc/termcap. In this +	 * case it better start with a "/". Or it can be an entry to +	 * use so we don't have to read the file. In this case it +	 * has to already have the newlines crunched out.  If TERMCAP +	 * does not hold a file name then a path of names is searched +	 * instead.  The path is found in the TERMPATH variable, or +	 * becomes "$HOME/.termcap /etc/termcap" if no TERMPATH exists. +	 */ +	if (!cp || *cp != '/') {	/* no TERMCAP or it holds an entry */ +		if (termpath = getenv("TERMPATH")) +			strncpy(pathbuf, termpath, PBUFSIZ); +		else { +			if (home = getenv("HOME")) {	/* set up default */ +				p += strlen(home);	/* path, looking in */ +				strcpy(pathbuf, home);	/* $HOME first */ +				*p++ = '/'; +			}	/* if no $HOME look in current directory */ +			strncpy(p, _PATH_DEF, PBUFSIZ - (p - pathbuf)); +		} +	} +	else				/* user-defined name in TERMCAP */ +		strncpy(pathbuf, cp, PBUFSIZ);	/* still can be tokenized */ + +	*fname++ = pathbuf;	/* tokenize path into vector of names */ +	while (*++p) +		if (*p == ' ' || *p == ':') { +			*p = '\0'; +			while (*++p) +				if (*p != ' ' && *p != ':') +					break; +			if (*p == '\0') +				break; +			*fname++ = p; +			if (fname >= pathvec + PVECSIZ) { +				fname--; +				break; +			} +		} +	*fname = (char *) 0;			/* mark end of vector */ +	if (cp && *cp && *cp != '/') +		if (cgetset(cp) < 0) +			return(-2); + +	i = cgetent(&dummy, pathvec, name);       +	 +	if (i == 0) +		strcpy(bp, dummy); +	 +	if (dummy) +		free(dummy); +	/* no tc reference loop return code in libterm XXX */ +	if (i == -3) +		return(-1); +	return(i + 1); +} + +/* + * Return the (numeric) option id. + * Numeric options look like + *	li#80 + * i.e. the option string is separated from the numeric value by + * a # character.  If the option is not found we return -1. + * Note that we handle octal numbers beginning with 0. + */ +int +tgetnum(id) +	char *id; +{ +	long num; + +	if (cgetnum(tbuf, id, &num) == 0) +		return(num); +	else +		return(-1); +} + +/* + * Handle a flag option. + * Flag options are given "naked", i.e. followed by a : or the end + * of the buffer.  Return 1 if we find the option, or 0 if it is + * not given. + */ +int +tgetflag(id) +	char *id; +{ +	return(cgetcap(tbuf, id, ':') != NULL); +} + +/* + * Get a string valued option. + * These are given as + *	cl=^Z + * Much decoding is done on the strings, and the strings are + * placed in area, which is a ref parameter which is updated. + * No checking on area overflow. + */ +char * +tgetstr(id, area) +	char *id, **area; +{ +	char ids[3]; +	char *s; +	int i; +	 +	/* +	 * XXX +	 * This is for all the boneheaded programs that relied on tgetstr +	 * to look only at the first 2 characters of the string passed... +	 */ +	*ids = *id; +	ids[1] = id[1]; +	ids[2] = '\0'; + +	if ((i = cgetstr(tbuf, ids, &s)) < 0) +		return NULL; +	 +	strcpy(*area, s); +	*area += i + 1; +	return(s); +} diff --git a/lib/libterm/tgoto.c b/lib/libterm/tgoto.c new file mode 100644 index 000000000000..f0e4cc4fe311 --- /dev/null +++ b/lib/libterm/tgoto.c @@ -0,0 +1,207 @@ +/* + * Copyright (c) 1980, 1993 + *	The 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 sccsid[] = "@(#)tgoto.c	8.1 (Berkeley) 6/4/93"; +#endif /* not lint */ + +#define	CTRL(c)	((c) & 037) + +#define MAXRETURNSIZE 64 + +char	*UP; +char	*BC; + +/* + * Routine to perform cursor addressing. + * CM is a string containing printf type escapes to allow + * cursor addressing.  We start out ready to print the destination + * line, and switch each time we print row or column. + * The following escapes are defined for substituting row/column: + * + *	%d	as in printf + *	%2	like %2d + *	%3	like %3d + *	%.	gives %c hacking special case characters + *	%+x	like %c but adding x first + * + *	The codes below affect the state but don't use up a value. + * + *	%>xy	if value > x add y + *	%r	reverses row/column + *	%i	increments row/column (for one origin indexing) + *	%%	gives % + *	%B	BCD (2 decimal digits encoded in one byte) + *	%D	Delta Data (backwards bcd) + * + * all other characters are ``self-inserting''. + */ +char * +tgoto(CM, destcol, destline) +	char *CM; +	int destcol, destline; +{ +	static char result[MAXRETURNSIZE]; +	static char added[10]; +	char *cp = CM; +	register char *dp = result; +	register int c; +	int oncol = 0; +	register int which = destline; + +	if (cp == 0) { +toohard: +		/* +		 * ``We don't do that under BOZO's big top'' +		 */ +		return ("OOPS"); +	} +	added[0] = 0; +	while (c = *cp++) { +		if (c != '%') { +			*dp++ = c; +			continue; +		} +		switch (c = *cp++) { + +#ifdef CM_N +		case 'n': +			destcol ^= 0140; +			destline ^= 0140; +			goto setwhich; +#endif + +		case 'd': +			if (which < 10) +				goto one; +			if (which < 100) +				goto two; +			/* fall into... */ + +		case '3': +			*dp++ = (which / 100) | '0'; +			which %= 100; +			/* fall into... */ + +		case '2': +two:	 +			*dp++ = which / 10 | '0'; +one: +			*dp++ = which % 10 | '0'; +swap: +			oncol = 1 - oncol; +setwhich: +			which = oncol ? destcol : destline; +			continue; + +#ifdef CM_GT +		case '>': +			if (which > *cp++) +				which += *cp++; +			else +				cp++; +			continue; +#endif + +		case '+': +			which += *cp++; +			/* fall into... */ + +		case '.': +casedot: +			/* +			 * This code is worth scratching your head at for a +			 * while.  The idea is that various weird things can +			 * happen to nulls, EOT's, tabs, and newlines by the +			 * tty driver, arpanet, and so on, so we don't send +			 * them if we can help it. +			 * +			 * Tab is taken out to get Ann Arbors to work, otherwise +			 * when they go to column 9 we increment which is wrong +			 * because bcd isn't continuous.  We should take out +			 * the rest too, or run the thing through more than +			 * once until it doesn't make any of these, but that +			 * would make termlib (and hence pdp-11 ex) bigger, +			 * and also somewhat slower.  This requires all +			 * programs which use termlib to stty tabs so they +			 * don't get expanded.  They should do this anyway +			 * because some terminals use ^I for other things, +			 * like nondestructive space. +			 */ +			if (which == 0 || which == CTRL('d') || /* which == '\t' || */ which == '\n') { +				if (oncol || UP) /* Assumption: backspace works */ +					/* +					 * Loop needed because newline happens +					 * to be the successor of tab. +					 */ +					do { +						strcat(added, oncol ? (BC ? BC : "\b") : UP); +						which++; +					} while (which == '\n'); +			} +			*dp++ = which; +			goto swap; + +		case 'r': +			oncol = 1; +			goto setwhich; + +		case 'i': +			destcol++; +			destline++; +			which++; +			continue; + +		case '%': +			*dp++ = c; +			continue; + +#ifdef CM_B +		case 'B': +			which = (which/10 << 4) + which%10; +			continue; +#endif + +#ifdef CM_D +		case 'D': +			which = which - 2 * (which%16); +			continue; +#endif + +		default: +			goto toohard; +		} +	} +	strcpy(dp, added); +	return (result); +} diff --git a/lib/libterm/tputs.c b/lib/libterm/tputs.c new file mode 100644 index 000000000000..857147d9283e --- /dev/null +++ b/lib/libterm/tputs.c @@ -0,0 +1,123 @@ +/* + * Copyright (c) 1980, 1993 + *	The 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 sccsid[] = "@(#)tputs.c	8.1 (Berkeley) 6/4/93"; +#endif /* not lint */ + +#include <sgtty.h> +#include <ctype.h> + +/* + * The following array gives the number of tens of milliseconds per + * character for each speed as returned by gtty.  Thus since 300 + * baud returns a 7, there are 33.3 milliseconds per char at 300 baud. + */ +static +short	tmspc10[] = { +	0, 2000, 1333, 909, 743, 666, 500, 333, 166, 83, 55, 41, 20, 10, 5 +}; + +short	ospeed; +char	PC; + +/* + * Put the character string cp out, with padding. + * The number of affected lines is affcnt, and the routine + * used to output one character is outc. + */ +tputs(cp, affcnt, outc) +	register char *cp; +	int affcnt; +	int (*outc)(); +{ +	register int i = 0; +	register int mspc10; + +	if (cp == 0) +		return; + +	/* +	 * Convert the number representing the delay. +	 */ +	if (isdigit(*cp)) { +		do +			i = i * 10 + *cp++ - '0'; +		while (isdigit(*cp)); +	} +	i *= 10; +	if (*cp == '.') { +		cp++; +		if (isdigit(*cp)) +			i += *cp - '0'; +		/* +		 * Only one digit to the right of the decimal point. +		 */ +		while (isdigit(*cp)) +			cp++; +	} + +	/* +	 * If the delay is followed by a `*', then +	 * multiply by the affected lines count. +	 */ +	if (*cp == '*') +		cp++, i *= affcnt; + +	/* +	 * The guts of the string. +	 */ +	while (*cp) +		(*outc)(*cp++); + +	/* +	 * If no delay needed, or output speed is +	 * not comprehensible, then don't try to delay. +	 */ +	if (i == 0) +		return; +	if (ospeed <= 0 || ospeed >= (sizeof tmspc10 / sizeof tmspc10[0])) +		return; + +	/* +	 * Round up by a half a character frame, +	 * and then do the delay. +	 * Too bad there are no user program accessible programmed delays. +	 * Transmitting pad characters slows many +	 * terminals down and also loads the system. +	 */ +	mspc10 = tmspc10[ospeed]; +	i += mspc10 / 2; +	for (i /= mspc10; i > 0; i--) +		(*outc)(PC); +} diff --git a/lib/libutil/pty.c b/lib/libutil/pty.c new file mode 100644 index 000000000000..6104461809ca --- /dev/null +++ b/lib/libutil/pty.c @@ -0,0 +1,128 @@ +/*- + * Copyright (c) 1990, 1993, 1994 + *	The 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. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static char sccsid[] = "@(#)pty.c	8.3 (Berkeley) 5/16/94"; +#endif /* LIBC_SCCS and not lint */ + +#include <sys/types.h> +#include <sys/ioctl.h> +#include <sys/stat.h> + +#include <errno.h> +#include <fcntl.h> +#include <grp.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <termios.h> +#include <unistd.h> + +openpty(amaster, aslave, name, termp, winp) +	int *amaster, *aslave; +	char *name; +	struct termios *termp; +	struct winsize *winp; +{ +	static char line[] = "/dev/ptyXX"; +	register const char *cp1, *cp2; +	register int master, slave, ttygid; +	struct group *gr; + +	if ((gr = getgrnam("tty")) != NULL) +		ttygid = gr->gr_gid; +	else +		ttygid = -1; + +	for (cp1 = "pqrs"; *cp1; cp1++) { +		line[8] = *cp1; +		for (cp2 = "0123456789abcdef"; *cp2; cp2++) { +			line[5] = 'p'; +			line[9] = *cp2; +			if ((master = open(line, O_RDWR, 0)) == -1) { +				if (errno == ENOENT) +					return (-1);	/* out of ptys */ +			} else { +				line[5] = 't'; +				(void) chown(line, getuid(), ttygid); +				(void) chmod(line, S_IRUSR|S_IWUSR|S_IWGRP); +				(void) revoke(line); +				if ((slave = open(line, O_RDWR, 0)) != -1) { +					*amaster = master; +					*aslave = slave; +					if (name) +						strcpy(name, line); +					if (termp) +						(void) tcsetattr(slave,  +							TCSAFLUSH, termp); +					if (winp) +						(void) ioctl(slave, TIOCSWINSZ,  +							(char *)winp); +					return (0); +				} +				(void) close(master); +			} +		} +	} +	errno = ENOENT;	/* out of ptys */ +	return (-1); +} + +forkpty(amaster, name, termp, winp) +	int *amaster; +	char *name; +	struct termios *termp; +	struct winsize *winp; +{ +	int master, slave, pid; + +	if (openpty(&master, &slave, name, termp, winp) == -1) +		return (-1); +	switch (pid = fork()) { +	case -1: +		return (-1); +	case 0: +		/*  +		 * child +		 */ +		(void) close(master); +		login_tty(slave); +		return (0); +	} +	/* +	 * parent +	 */ +	*amaster = master; +	(void) close(slave); +	return (pid); +}  | 
