mirror of git://sourceware.org/git/glibc.git
Update.
1998-07-28 Ulrich Drepper <drepper@cygnus.com> * math/libm-test.c (tgamma_test): Remove redundant tests. 1998-07-28 16:20 Ulrich Drepper <drepper@cygnus.com> * sysdeps/generic/glob.c: Correct problems with */foo and GLOB_NOCHECK where foo does not exist in any of the subdirectories. Reported by Paul D. Smith <psmith@BayNetworks.COM>. * posix/globtest.sh: Add test for this bug. 1998-07-28 Mark Kettenis <kettenis@phys.uva.nl> * io/sys/statfs.h: Fix typos. * io/sys/statvfs.h: Fix typos. 1998-07-28 Ulrich Drepper <drepper@cygnus.com> * version.h (VERSION): Bump to 2.0.95. * math/Makefile (libm-calls): Remove w_gamma, add w_tgamma. * math/Versions [GLIBC_2.1]: Add tgamma, tgammaf, and tgammal. * math/libm-test.c: Split old gamma_test and move half of it in new function tgamma_test. * math/bits/mathcalls.h: Add declaration of tgamma. * sysdeps/libm-ieee754/k_standard.c: Change gamma errors into tgamma errors. * sysdeps/libm-ieee754/w_gamma.c: Remove lgamma compatibility code and rename to ... * sysdeps/libm-ieee754/w_tgamma.c: ... this. New file. * sysdeps/libm-ieee754/w_gammaf.c: Remove lgammaf compatibility code and rename to ... * sysdeps/libm-ieee754/w_tgammaf.c: ... this. New file. * sysdeps/libm-ieee754/w_gammal.c: Remove lgammal compatibility code and rename to ... * sysdeps/libm-ieee754/w_tgammal.c: ... this. New file. * sysdeps/libm-ieee754/w_lgamma.c: Add gamma as weak alias. * sysdeps/libm-ieee754/w_lgammaf.c: Likewise. * sysdeps/libm-ieee754/w_lgammal.c: Likewise. * stgdio-common/printf-parse.h: Implement handling of j, t, and z modifiers. * stdio-common/vfprintf.c: Likewise. * stdio-common/vfscanf.c: Likewise. * manual/stdio.texi: Document new printf/scanf modifiers. * sysdeps/unix/sysv/linux/recvmsg.c: Remove alias __recvmsg. * sysdeps/unix/sysv/linux/sendmsg.c: Remove alias __sendmsg. 1998-07-28 Thorsten Kukuk <kukuk@vt.uni-paderborn.de> * sunrpc/Makefile (routines): Add clnt_unix and svc_unix. * sunrpc/Versions: Add new *unix_create functions. * sunrpc/clnt_gen.c: Add support for RPC over AF_UNIX. * sunrpc/clnt_unix.c: New, client side of RPC over AF_UNIX. * sunrpc/key_call.c: Use RPC over AF_UNIX for communication with keyserv daemon. * sunrpc/rpc/clnt.h: Add AF_UNIX based RPC function prototypes. * sunrpc/rpc/svc.h: Likewise. * sunrpc/svc_authux.c: Copy internal auth flavor if none is given. * sunrpc/svc_tcp.c: Fix typos. * sunrpc/svc_unix.c: New, server side of AF_UNIX based RPC. * nis/Makefile: Remove currently not working cache functions. * nis/Versions: Add __nisbind_* functions for rpc.nisd. * nis/nis_call.c: Rewrite binding to a NIS+ server to reuse CLIENT handles. * nis/nis_file.c: Fix memory leaks. * nis/nis_intern.h: Move internal structs from here ... * nis/rpcsvc/nislib.h: ... to here for NIS+ server and tools. * nis/nis_lookup.c: Try at first if last client handle works. * nis/nis_table.c: Likewise. * nis/nis_checkpoint.c: Adjust __do_niscall2 parameters. * nis/nis_mkdir.c: Likewise. * nis/nis_ping.c: Likewise. * nis/nis_rmdir.c: Likewise. * nis/nis_server.c: Likewise. * nis/nis_util.c: Likewise. * nis/nis_findserv.c (__nis_findfastest): Little optimization. 1998-07-28 Andreas Jaeger <aj@arthur.rhein-neckar.de> * stdlib/strtol.c (STRTOL_LONG_MAX): Correct typo in last patch - define as LONG_MAX. 1998-07-28 09:31 Ulrich Drepper <drepper@cygnus.com> * nscd/connections.c (gr_send_answer): Deal with missing UIO_MAXIOV. Correct test whether writev send all data. * nscd/nscd_getgr_r.c (__nscd_getgr_r): Correct test whether readv received all data. 1998-07-28 Mark Kettenis <kettenis@phys.uva.nl> * nscd/nscd_getgr_r.c (__nscd_getgr_r): Deal with missing UIO_MAXIOV. 1998-07-28 Mark Kettenis <kettenis@phys.uva.nl> * sysdeps/mach/hurd/dl-sysdep.c (open_file): Change assert call to allow mode to be 0. (__xstat): New function. (__fxstat): New function. (_dl_sysdep_read_whole_file): Removed. The implementation in `elf/dl-misc.c' now also works for the Hurd.
This commit is contained in:
parent
c9243dacea
commit
e852e88944
106
ChangeLog
106
ChangeLog
|
@ -1,3 +1,109 @@
|
|||
1998-07-28 Ulrich Drepper <drepper@cygnus.com>
|
||||
|
||||
* math/libm-test.c (tgamma_test): Remove redundant tests.
|
||||
|
||||
1998-07-28 16:20 Ulrich Drepper <drepper@cygnus.com>
|
||||
|
||||
* sysdeps/generic/glob.c: Correct problems with */foo and GLOB_NOCHECK
|
||||
where foo does not exist in any of the subdirectories.
|
||||
Reported by Paul D. Smith <psmith@BayNetworks.COM>.
|
||||
|
||||
* posix/globtest.sh: Add test for this bug.
|
||||
|
||||
1998-07-28 Mark Kettenis <kettenis@phys.uva.nl>
|
||||
|
||||
* io/sys/statfs.h: Fix typos.
|
||||
* io/sys/statvfs.h: Fix typos.
|
||||
|
||||
1998-07-28 Ulrich Drepper <drepper@cygnus.com>
|
||||
|
||||
* version.h (VERSION): Bump to 2.0.95.
|
||||
|
||||
* math/Makefile (libm-calls): Remove w_gamma, add w_tgamma.
|
||||
* math/Versions [GLIBC_2.1]: Add tgamma, tgammaf, and tgammal.
|
||||
* math/libm-test.c: Split old gamma_test and move half of it in new
|
||||
function tgamma_test.
|
||||
* math/bits/mathcalls.h: Add declaration of tgamma.
|
||||
* sysdeps/libm-ieee754/k_standard.c: Change gamma errors into
|
||||
tgamma errors.
|
||||
* sysdeps/libm-ieee754/w_gamma.c: Remove lgamma compatibility code
|
||||
and rename to ...
|
||||
* sysdeps/libm-ieee754/w_tgamma.c: ... this. New file.
|
||||
* sysdeps/libm-ieee754/w_gammaf.c: Remove lgammaf compatibility code
|
||||
and rename to ...
|
||||
* sysdeps/libm-ieee754/w_tgammaf.c: ... this. New file.
|
||||
* sysdeps/libm-ieee754/w_gammal.c: Remove lgammal compatibility code
|
||||
and rename to ...
|
||||
* sysdeps/libm-ieee754/w_tgammal.c: ... this. New file.
|
||||
* sysdeps/libm-ieee754/w_lgamma.c: Add gamma as weak alias.
|
||||
* sysdeps/libm-ieee754/w_lgammaf.c: Likewise.
|
||||
* sysdeps/libm-ieee754/w_lgammal.c: Likewise.
|
||||
|
||||
* stgdio-common/printf-parse.h: Implement handling of j, t, and z
|
||||
modifiers.
|
||||
* stdio-common/vfprintf.c: Likewise.
|
||||
* stdio-common/vfscanf.c: Likewise.
|
||||
* manual/stdio.texi: Document new printf/scanf modifiers.
|
||||
|
||||
* sysdeps/unix/sysv/linux/recvmsg.c: Remove alias __recvmsg.
|
||||
* sysdeps/unix/sysv/linux/sendmsg.c: Remove alias __sendmsg.
|
||||
|
||||
1998-07-28 Thorsten Kukuk <kukuk@vt.uni-paderborn.de>
|
||||
|
||||
* sunrpc/Makefile (routines): Add clnt_unix and svc_unix.
|
||||
* sunrpc/Versions: Add new *unix_create functions.
|
||||
* sunrpc/clnt_gen.c: Add support for RPC over AF_UNIX.
|
||||
* sunrpc/clnt_unix.c: New, client side of RPC over AF_UNIX.
|
||||
* sunrpc/key_call.c: Use RPC over AF_UNIX for communication
|
||||
with keyserv daemon.
|
||||
* sunrpc/rpc/clnt.h: Add AF_UNIX based RPC function prototypes.
|
||||
* sunrpc/rpc/svc.h: Likewise.
|
||||
* sunrpc/svc_authux.c: Copy internal auth flavor if none is given.
|
||||
* sunrpc/svc_tcp.c: Fix typos.
|
||||
* sunrpc/svc_unix.c: New, server side of AF_UNIX based RPC.
|
||||
|
||||
* nis/Makefile: Remove currently not working cache functions.
|
||||
* nis/Versions: Add __nisbind_* functions for rpc.nisd.
|
||||
* nis/nis_call.c: Rewrite binding to a NIS+ server to reuse
|
||||
CLIENT handles.
|
||||
* nis/nis_file.c: Fix memory leaks.
|
||||
* nis/nis_intern.h: Move internal structs from here ...
|
||||
* nis/rpcsvc/nislib.h: ... to here for NIS+ server and tools.
|
||||
* nis/nis_lookup.c: Try at first if last client handle works.
|
||||
* nis/nis_table.c: Likewise.
|
||||
* nis/nis_checkpoint.c: Adjust __do_niscall2 parameters.
|
||||
* nis/nis_mkdir.c: Likewise.
|
||||
* nis/nis_ping.c: Likewise.
|
||||
* nis/nis_rmdir.c: Likewise.
|
||||
* nis/nis_server.c: Likewise.
|
||||
* nis/nis_util.c: Likewise.
|
||||
* nis/nis_findserv.c (__nis_findfastest): Little optimization.
|
||||
|
||||
1998-07-28 Andreas Jaeger <aj@arthur.rhein-neckar.de>
|
||||
|
||||
* stdlib/strtol.c (STRTOL_LONG_MAX): Correct typo in last patch -
|
||||
define as LONG_MAX.
|
||||
|
||||
1998-07-28 09:31 Ulrich Drepper <drepper@cygnus.com>
|
||||
|
||||
* nscd/connections.c (gr_send_answer): Deal with missing UIO_MAXIOV.
|
||||
Correct test whether writev send all data.
|
||||
* nscd/nscd_getgr_r.c (__nscd_getgr_r): Correct test whether readv
|
||||
received all data.
|
||||
|
||||
1998-07-28 Mark Kettenis <kettenis@phys.uva.nl>
|
||||
|
||||
* nscd/nscd_getgr_r.c (__nscd_getgr_r): Deal with missing UIO_MAXIOV.
|
||||
|
||||
1998-07-28 Mark Kettenis <kettenis@phys.uva.nl>
|
||||
|
||||
* sysdeps/mach/hurd/dl-sysdep.c (open_file): Change assert call to
|
||||
allow mode to be 0.
|
||||
(__xstat): New function.
|
||||
(__fxstat): New function.
|
||||
(_dl_sysdep_read_whole_file): Removed. The implementation in
|
||||
`elf/dl-misc.c' now also works for the Hurd.
|
||||
|
||||
1998-07-27 22:25 Ulrich Drepper <drepper@cygnus.com>
|
||||
|
||||
* sysdeps/generic/glob.c: Handle ~ and ~NAME case correctly.
|
||||
|
|
|
@ -857,7 +857,8 @@ The sign of the gamma function is stored in the global variable
|
|||
the intermediate result was positive or zero, and, @code{-1} if it was
|
||||
negative.
|
||||
|
||||
You can compute the actual gamma function as follows:
|
||||
To compute the real gamma function you can use the @code{tgamma}
|
||||
function or you can compute the values as follows:
|
||||
@smallexample
|
||||
lgam = lgamma(x);
|
||||
gam = signgam*exp(lgam);
|
||||
|
@ -878,15 +879,35 @@ the intermediate result in the variable pointed to by @var{signp}
|
|||
instead of in the @var{signgam} global.
|
||||
@end deftypefun
|
||||
|
||||
@ignore
|
||||
@comment math.h
|
||||
@comment SVID
|
||||
@deftypefun double gamma (double @var{x})
|
||||
@deftypefunx float gammaf (float @var{x})
|
||||
@deftypefunx {long double} gammal (long double @var{x})
|
||||
??? _not_ exp(lgamma())*signgam - historical?
|
||||
These functions exist for compatibility reasons. They are equivalent to
|
||||
@code{lgamma} etc. It is better to use @code{lgamma} since for one the
|
||||
name reflect better the actual computation and @code{lgamma} is also
|
||||
standardized in @w{ISO C 9x} while @code{gamma} is not.
|
||||
@end deftypefun
|
||||
|
||||
@comment math.h
|
||||
@comment XPG
|
||||
@deftypefun double tgamma (double @var{x})
|
||||
@deftypefunx float tgammaf (float @var{x})
|
||||
@deftypefunx {long double} tgammal (long double @var{x})
|
||||
@code{tgamma} applies the gamma function to @var{x}. The gamma
|
||||
function is defined as
|
||||
@tex
|
||||
$$\Gamma(x) = \int_0^\infty t^{x-1} e^{-t} \hbox{d}t$$
|
||||
@end tex
|
||||
@ifnottex
|
||||
@smallexample
|
||||
gamma (x) = integral from 0 to @infinity{} of t^(x-1) e^-t dt
|
||||
@end smallexample
|
||||
@end ifnottex
|
||||
|
||||
This function was introduced in @w{ISO C 9x}.
|
||||
@end deftypefun
|
||||
@end ignore
|
||||
|
||||
@comment math.h
|
||||
@comment SVID
|
||||
|
|
|
@ -1190,6 +1190,8 @@ char}, as appropriate. A @code{char} argument is converted to an
|
|||
anyway, but the @samp{h} modifier says to convert it back to a
|
||||
@code{char} again.
|
||||
|
||||
This modifier was introduced in @w{ISO C 9x}.
|
||||
|
||||
@item h
|
||||
Specifies that the argument is a @code{short int} or @code{unsigned
|
||||
short int}, as appropriate. A @code{short} argument is converted to an
|
||||
|
@ -1197,6 +1199,12 @@ short int}, as appropriate. A @code{short} argument is converted to an
|
|||
anyway, but the @samp{h} modifier says to convert it back to a
|
||||
@code{short} again.
|
||||
|
||||
@item j
|
||||
Specifies that the argument is a @code{intmax_t} or @code{uintmax_t}, as
|
||||
appropriate.
|
||||
|
||||
This modifier was introduced in @w{ISO C 9x}.
|
||||
|
||||
@item l
|
||||
Specifies that the argument is a @code{long int} or @code{unsigned long
|
||||
int}, as appropriate. Two @samp{l} characters is like the @samp{L}
|
||||
|
@ -1213,8 +1221,17 @@ The @samp{q} modifier is another name for the same thing, which comes
|
|||
from 4.4 BSD; a @w{@code{long long int}} is sometimes called a ``quad''
|
||||
@code{int}.
|
||||
|
||||
@item Z
|
||||
Specifies that the argument is a @code{size_t}. This is a GNU extension.
|
||||
@item t
|
||||
Specifies that the argument is a @code{ptrdiff_t}.
|
||||
|
||||
This modifier was introduced in @w{ISO C 9x}.
|
||||
|
||||
@item z
|
||||
@itemx Z
|
||||
Specifies that the argument is a @code{size_t}.
|
||||
|
||||
@samp{z} was introduced in @w{ISO C 9x}. @samp{Z} is a GNU extension
|
||||
predating this addition and should not be used anymore in new code.
|
||||
@end table
|
||||
|
||||
Here is an example. Using the template string:
|
||||
|
@ -2653,10 +2670,17 @@ specify other sizes of integer:
|
|||
Specifies that the argument is a @code{signed char *} or @code{unsigned
|
||||
char *}.
|
||||
|
||||
This modifier was introduced in @w{ISO C 9x}.
|
||||
|
||||
@item h
|
||||
Specifies that the argument is a @code{short int *} or @code{unsigned
|
||||
short int *}.
|
||||
|
||||
@item j
|
||||
Specifies that the argument is a @code{intmax_t *} or @code{uintmax_t *}.
|
||||
|
||||
This modifier was introduced in @w{ISO C 9x}.
|
||||
|
||||
@item l
|
||||
Specifies that the argument is a @code{long int *} or @code{unsigned
|
||||
long int *}. Two @samp{l} characters is like the @samp{L} modifier, below.
|
||||
|
@ -2672,6 +2696,16 @@ is the same as @code{long int}.)
|
|||
The @samp{q} modifier is another name for the same thing, which comes
|
||||
from 4.4 BSD; a @w{@code{long long int}} is sometimes called a ``quad''
|
||||
@code{int}.
|
||||
|
||||
@item t
|
||||
Specifies that the argument is a @code{ptrdiff_t *}.
|
||||
|
||||
This modifier was introduced in @w{ISO C 9x}.
|
||||
|
||||
@item z
|
||||
Specifies that the argument is a @code{size_t *}.
|
||||
|
||||
This modifier was introduced in @w{ISO C 9x}.
|
||||
@end table
|
||||
|
||||
All of the @samp{%e}, @samp{%f}, @samp{%g}, @samp{%E}, and @samp{%G}
|
||||
|
|
|
@ -49,7 +49,7 @@ libm-calls = e_acos e_acosh e_asin e_atan2 e_atanh e_cosh e_exp e_fmod \
|
|||
s_modf s_nextafter s_nextafterx s_rint s_scalbn s_scalbln \
|
||||
s_significand s_sin s_tan s_tanh w_acos w_acosh w_asin \
|
||||
w_atan2 w_atanh w_cosh w_drem w_exp w_exp2 w_exp10 w_fmod \
|
||||
w_gamma w_hypot w_j0 w_j1 w_jn w_lgamma w_lgamma_r \
|
||||
w_tgamma w_hypot w_j0 w_j1 w_jn w_lgamma w_lgamma_r \
|
||||
w_log w_log10 w_pow w_remainder w_scalb w_sinh w_sqrt \
|
||||
s_signbit s_fpclassify s_fmax s_fmin s_fdim s_nan s_trunc \
|
||||
s_remquo s_log2 s_exp2 s_round s_nearbyint s_sincos \
|
||||
|
|
|
@ -111,6 +111,7 @@ libm {
|
|||
scalbln; scalblnf; scalblnl;
|
||||
sincos; sincosf; sincosl;
|
||||
trunc; truncf; truncl;
|
||||
tgamma; tgammaf; tgammal;
|
||||
|
||||
# complex functions
|
||||
cabs; cabsf; cabsl;
|
||||
|
|
|
@ -224,8 +224,12 @@ __MATHCALL (yn,, (int, _Mdouble_));
|
|||
/* Error, gamma, and Bessel functions. */
|
||||
__MATHCALL (erf,, (_Mdouble_));
|
||||
__MATHCALL (erfc,, (_Mdouble_));
|
||||
__MATHCALL (gamma,, (_Mdouble_));
|
||||
__MATHCALL (lgamma,, (_Mdouble_));
|
||||
__MATHCALL (tgamma,, (_Mdouble_));
|
||||
#endif
|
||||
|
||||
#if defined __USE_MISC || defined __USE_XOPEN
|
||||
__MATHCALL (gamma,, (_Mdouble_));
|
||||
#endif
|
||||
|
||||
#ifdef __USE_MISC
|
||||
|
|
|
@ -51,7 +51,7 @@
|
|||
modf, nearbyint, nextafter,
|
||||
pow, remainder, remquo, rint, lrint, llrint,
|
||||
round, lround, llround,
|
||||
scalb, scalbn, signbit, sin, sincos, sinh, sqrt, tan, tanh, trunc
|
||||
scalb, scalbn, signbit, sin, sincos, sinh, sqrt, tan, tanh, tgamma, trunc
|
||||
|
||||
and for the following complex math functions:
|
||||
cabs, cacos, cacosh, carg, casin, casinh, catan, catanh,
|
||||
|
@ -1413,15 +1413,9 @@ signbit_test (void)
|
|||
}
|
||||
|
||||
|
||||
/*
|
||||
gamma has different semantics depending on _LIB_VERSION:
|
||||
if _LIB_VERSION is _SVID, gamma is just an alias for lgamma,
|
||||
otherwise gamma is the real gamma function as definied in ISO C 9X.
|
||||
*/
|
||||
static void
|
||||
gamma_test (void)
|
||||
{
|
||||
int save_lib_version = _LIB_VERSION;
|
||||
errno = 0;
|
||||
FUNC(gamma) (1);
|
||||
if (errno == ENOSYS)
|
||||
|
@ -1430,14 +1424,12 @@ gamma_test (void)
|
|||
feclearexcept (FE_ALL_EXCEPT);
|
||||
|
||||
|
||||
_LIB_VERSION = _SVID_;
|
||||
|
||||
check_isinfp ("gamma (+inf) == +inf", FUNC(gamma) (plus_infty));
|
||||
check_exc ("gamma (0) == HUGE plus divide by zero exception",
|
||||
FUNC(gamma) (0), HUGE, DIVIDE_BY_ZERO_EXCEPTION);
|
||||
check_isinfp_exc ("gamma (0) == +inf plus divide by zero exception",
|
||||
FUNC(gamma) (0), DIVIDE_BY_ZERO_EXCEPTION);
|
||||
|
||||
check_exc ("gamma (x) == HUGE plus divide by zero exception for integer x <= 0",
|
||||
FUNC(gamma) (-3), HUGE, DIVIDE_BY_ZERO_EXCEPTION);
|
||||
check_isinfp_exc ("gamma (x) == +inf plus divide by zero exception for integer x <= 0",
|
||||
FUNC(gamma) (-3), DIVIDE_BY_ZERO_EXCEPTION);
|
||||
check_isnan_exc ("gamma (-inf) == NaN plus invalid exception",
|
||||
FUNC(gamma) (minus_infty), INVALID_EXCEPTION);
|
||||
|
||||
|
@ -1459,39 +1451,43 @@ gamma_test (void)
|
|||
FUNC(log) (2*FUNC(sqrt) (M_PIl)), CHOOSE (0, 1e-15, 0));
|
||||
|
||||
check_int ("gamma (-0.5) sets signgam to -1", signgam, -1);
|
||||
}
|
||||
|
||||
|
||||
_LIB_VERSION = _IEEE_;
|
||||
static void
|
||||
tgamma_test (void)
|
||||
{
|
||||
errno = 0;
|
||||
FUNC(tgamma) (1);
|
||||
if (errno == ENOSYS)
|
||||
/* Function not implemented. */
|
||||
return;
|
||||
feclearexcept (FE_ALL_EXCEPT);
|
||||
|
||||
check_isinfp ("gamma (+inf) == +inf", FUNC(gamma) (plus_infty));
|
||||
check_isnan_exc ("gamma (0) == NaN plus invalid exception",
|
||||
FUNC(gamma) (0), INVALID_EXCEPTION);
|
||||
|
||||
check_isnan_exc_ext ("gamma (x) == NaN plus invalid exception for integer x <= 0",
|
||||
FUNC(gamma) (-2), INVALID_EXCEPTION, -2);
|
||||
check_isnan_exc ("gamma (-inf) == NaN plus invalid exception",
|
||||
FUNC(gamma) (minus_infty), INVALID_EXCEPTION);
|
||||
check_isinfp ("tgamma (+inf) == +inf", FUNC(tgamma) (plus_infty));
|
||||
check_isnan_exc ("tgamma (0) == NaN plus invalid exception",
|
||||
FUNC(tgamma) (0), INVALID_EXCEPTION);
|
||||
|
||||
check_isnan_exc_ext ("tgamma (x) == NaN plus invalid exception for integer x <= 0",
|
||||
FUNC(tgamma) (-2), INVALID_EXCEPTION, -2);
|
||||
check_isnan_exc ("tgamma (-inf) == NaN plus invalid exception",
|
||||
FUNC(tgamma) (minus_infty), INVALID_EXCEPTION);
|
||||
|
||||
#ifdef TODO
|
||||
check_eps ("gamma (0.5) == sqrt(pi)", FUNC(gamma) (0.5), FUNC(sqrt) (M_PIl),
|
||||
CHOOSE (0, 5e-16, 2e-7));
|
||||
check_eps ("tgamma (0.5) == sqrt(pi)", FUNC(tgamma) (0.5),
|
||||
FUNC(sqrt) (M_PIl), CHOOSE (0, 5e-16, 2e-7));
|
||||
#endif
|
||||
check_eps ("gamma (-0.5) == -2*sqrt(pi)", FUNC(gamma) (-0.5),
|
||||
check_eps ("tgamma (-0.5) == -2*sqrt(pi)", FUNC(tgamma) (-0.5),
|
||||
-2*FUNC(sqrt) (M_PIl), CHOOSE (0, 5e-16, 3e-7));
|
||||
|
||||
check ("gamma (1) == 1", FUNC(gamma) (1), 1);
|
||||
check ("gamma (4) == 6", FUNC(gamma) (4), 6);
|
||||
check ("tgamma (1) == 1", FUNC(tgamma) (1), 1);
|
||||
check ("tgamma (4) == 6", FUNC(tgamma) (4), 6);
|
||||
|
||||
check_eps ("gamma (0.7) == 1.29805...", FUNC(gamma) (0.7),
|
||||
check_eps ("tgamma (0.7) == 1.29805...", FUNC(tgamma) (0.7),
|
||||
1.29805533264755778568L, CHOOSE(0, 3e-16, 2e-7));
|
||||
check ("gamma (1.2) == 0.91816...", FUNC(gamma) (1.2), 0.91816874239976061064L);
|
||||
|
||||
check_isnan_exc ("gamma (0.0) == NaN plus invalid exception",
|
||||
FUNC(gamma) (0.0), INVALID_EXCEPTION);
|
||||
check_isnan_exc ("gamma (-1.0) == NaN plus invalid exception",
|
||||
FUNC(gamma) (-1.0), INVALID_EXCEPTION);
|
||||
|
||||
_LIB_VERSION = save_lib_version;
|
||||
check ("tgamma (1.2) == 0.91816...", FUNC(tgamma) (1.2),
|
||||
0.91816874239976061064L);
|
||||
}
|
||||
|
||||
|
||||
|
@ -6012,6 +6008,7 @@ main (int argc, char *argv[])
|
|||
erf_test ();
|
||||
erfc_test ();
|
||||
gamma_test ();
|
||||
tgamma_test ();
|
||||
lgamma_test ();
|
||||
|
||||
/* nearest integer functions */
|
||||
|
|
|
@ -1 +1 @@
|
|||
NIS(YP)/NIS+ NSS modules 0.17 by Thorsten Kukuk
|
||||
NIS(YP)/NIS+ NSS modules 0.18 by Thorsten Kukuk
|
||||
|
|
|
@ -23,7 +23,7 @@ subdir := nis
|
|||
|
||||
headers := $(wildcard rpcsvc/*.[hx])
|
||||
distribute := nss-nis.h nss-nisplus.h nis_intern.h Banner \
|
||||
nisplus-parser.h nis_cache2.h nis_xdr.h
|
||||
nisplus-parser.h nis_xdr.h
|
||||
|
||||
# These are the databases available for the nis (and perhaps later nisplus)
|
||||
# service. This must be a superset of the services in nss.
|
||||
|
@ -44,8 +44,8 @@ vpath %.c $(subdir-dirs)
|
|||
|
||||
libnsl-routines = yp_xdr ypclnt ypupdate_xdr \
|
||||
nis_subr nis_local_names nis_free nis_file \
|
||||
nis_print nis_error nis_call nis_lookup nis_cache\
|
||||
nis_table nis_xdr nis_server nis_ping nis_cache2_xdr\
|
||||
nis_print nis_error nis_call nis_lookup\
|
||||
nis_table nis_xdr nis_server nis_ping \
|
||||
nis_checkpoint nis_mkdir nis_rmdir nis_getservlist\
|
||||
nis_verifygroup nis_ismember nis_addmember nis_util\
|
||||
nis_removemember nis_creategroup nis_destroygroup\
|
||||
|
|
|
@ -48,9 +48,10 @@ libnsl {
|
|||
|
||||
# This functions are needed by the NIS+ tools and rpc.nisd,
|
||||
# they should never be used in a normal user program !
|
||||
__do_niscall2; __free_fdresult; __nis_default_access;
|
||||
__nis_default_group; __nis_default_owner; __nis_default_ttl;
|
||||
__nis_finddirectory; __nis_hash;
|
||||
__free_fdresult; __nis_default_access; __nis_default_group;
|
||||
__nis_default_owner; __nis_default_ttl; __nis_finddirectory;
|
||||
__nis_hash; __nisbind_connect; __nisbind_create;
|
||||
__nisbind_destroy; __nisbind_next;
|
||||
readColdStartFile; writeColdStartFile;
|
||||
}
|
||||
}
|
||||
|
|
234
nis/nis_call.c
234
nis/nis_call.c
|
@ -60,8 +60,8 @@ inetstr2int (const char *str)
|
|||
return inet_addr (buffer);
|
||||
}
|
||||
|
||||
static void
|
||||
__bind_destroy (dir_binding *bind)
|
||||
void
|
||||
__nisbind_destroy (dir_binding *bind)
|
||||
{
|
||||
if (bind->clnt != NULL)
|
||||
{
|
||||
|
@ -71,8 +71,8 @@ __bind_destroy (dir_binding *bind)
|
|||
}
|
||||
}
|
||||
|
||||
static nis_error
|
||||
__bind_next (dir_binding *bind)
|
||||
nis_error
|
||||
__nisbind_next (dir_binding *bind)
|
||||
{
|
||||
u_int j;
|
||||
|
||||
|
@ -91,8 +91,7 @@ __bind_next (dir_binding *bind)
|
|||
j < bind->server_val[bind->server_used].ep.ep_len; ++j)
|
||||
if (strcmp (bind->server_val[bind->server_used].ep.ep_val[j].family,
|
||||
"inet") == 0)
|
||||
if (strcmp (bind->server_val[bind->server_used].ep.ep_val[j].proto,
|
||||
"-") == 0)
|
||||
if (bind->server_val[bind->server_used].ep.ep_val[j].proto[0] == '-')
|
||||
{
|
||||
bind->current_ep = j;
|
||||
return NIS_SUCCESS;
|
||||
|
@ -115,8 +114,8 @@ __bind_next (dir_binding *bind)
|
|||
return NIS_FAIL;
|
||||
}
|
||||
|
||||
static nis_error
|
||||
__bind_connect (dir_binding *dbp)
|
||||
nis_error
|
||||
__nisbind_connect (dir_binding *dbp)
|
||||
{
|
||||
nis_server *serv;
|
||||
|
||||
|
@ -157,7 +156,7 @@ __bind_connect (dir_binding *dbp)
|
|||
|
||||
if (dbp->use_auth)
|
||||
{
|
||||
if (serv->key_type == NIS_PK_DH && key_secretkey_is_set ())
|
||||
if (serv->key_type == NIS_PK_DH)
|
||||
{
|
||||
char netname[MAXNETNAMELEN+1];
|
||||
char *p;
|
||||
|
@ -180,9 +179,9 @@ __bind_connect (dir_binding *dbp)
|
|||
return NIS_SUCCESS;
|
||||
}
|
||||
|
||||
static nis_error
|
||||
__bind_create (dir_binding *dbp, const nis_server *serv_val, u_int serv_len,
|
||||
u_long flags, cache2_info *cinfo)
|
||||
nis_error
|
||||
__nisbind_create (dir_binding *dbp, const nis_server *serv_val, u_int serv_len,
|
||||
u_long flags)
|
||||
{
|
||||
dbp->clnt = NULL;
|
||||
|
||||
|
@ -208,54 +207,34 @@ __bind_create (dir_binding *dbp, const nis_server *serv_val, u_int serv_len,
|
|||
dbp->trys = 1;
|
||||
|
||||
dbp->class = -1;
|
||||
if (cinfo != NULL && cinfo->server_used >= 0)
|
||||
if (__nis_findfastest (dbp) < 1)
|
||||
{
|
||||
dbp->server_used = cinfo->server_used;
|
||||
dbp->current_ep = cinfo->current_ep;
|
||||
dbp->class = cinfo->class;
|
||||
}
|
||||
else if (__nis_findfastest (dbp) < 1)
|
||||
{
|
||||
__bind_destroy (dbp);
|
||||
__nisbind_destroy (dbp);
|
||||
return NIS_NAMEUNREACHABLE;
|
||||
}
|
||||
|
||||
return NIS_SUCCESS;
|
||||
}
|
||||
|
||||
/* __nisbind_connect (dbp) must be run before calling this function !
|
||||
So we could use the same binding twice */
|
||||
nis_error
|
||||
__do_niscall2 (const nis_server *server, u_int server_len, u_long prog,
|
||||
xdrproc_t xargs, caddr_t req, xdrproc_t xres, caddr_t resp,
|
||||
u_long flags, nis_cb *cb, cache2_info *cinfo)
|
||||
__do_niscall3 (dir_binding *dbp, u_long prog, xdrproc_t xargs, caddr_t req,
|
||||
xdrproc_t xres, caddr_t resp, u_long flags, nis_cb *cb)
|
||||
{
|
||||
enum clnt_stat result;
|
||||
nis_error retcode;
|
||||
dir_binding dbp;
|
||||
|
||||
if (flags & MASTER_ONLY)
|
||||
server_len = 1;
|
||||
|
||||
if (__bind_create (&dbp, server, server_len, flags, cinfo) != NIS_SUCCESS)
|
||||
if (dbp == NULL)
|
||||
return NIS_NAMEUNREACHABLE;
|
||||
while (__bind_connect (&dbp) != NIS_SUCCESS)
|
||||
{
|
||||
if (__bind_next (&dbp) != NIS_SUCCESS)
|
||||
{
|
||||
__bind_destroy (&dbp);
|
||||
return NIS_NAMEUNREACHABLE;
|
||||
}
|
||||
}
|
||||
|
||||
do
|
||||
{
|
||||
again:
|
||||
result = clnt_call (dbp.clnt, prog, xargs, req, xres, resp, RPCTIMEOUT);
|
||||
result = clnt_call (dbp->clnt, prog, xargs, req, xres, resp, RPCTIMEOUT);
|
||||
|
||||
if (result != RPC_SUCCESS)
|
||||
{
|
||||
__bind_destroy (&dbp);
|
||||
retcode = NIS_RPCERROR;
|
||||
}
|
||||
retcode = NIS_RPCERROR;
|
||||
else
|
||||
{
|
||||
switch (prog)
|
||||
|
@ -264,11 +243,11 @@ __do_niscall2 (const nis_server *server, u_int server_len, u_long prog,
|
|||
if ((((nis_result *)resp)->status == NIS_CBRESULTS) &&
|
||||
(cb != NULL))
|
||||
{
|
||||
__nis_do_callback(&dbp, &((nis_result *)resp)->cookie, cb);
|
||||
__nis_do_callback(dbp, &((nis_result *)resp)->cookie, cb);
|
||||
break;
|
||||
}
|
||||
/* Yes, this is correct. If we doesn't have to start
|
||||
a callback, look if we have to search another server */
|
||||
/* Yes, the missing break is correct. If we doesn't have to
|
||||
start a callback, look if we have to search another server */
|
||||
case NIS_LOOKUP:
|
||||
case NIS_ADD:
|
||||
case NIS_MODIFY:
|
||||
|
@ -278,19 +257,16 @@ __do_niscall2 (const nis_server *server, u_int server_len, u_long prog,
|
|||
case NIS_IBREMOVE:
|
||||
case NIS_IBFIRST:
|
||||
case NIS_IBNEXT:
|
||||
if ((((nis_result *)resp)->status == NIS_NOTFOUND) ||
|
||||
if ((((nis_result *)resp)->status == NIS_SYSTEMERROR) ||
|
||||
(((nis_result *)resp)->status == NIS_NOSUCHNAME) ||
|
||||
(((nis_result *)resp)->status == NIS_NOT_ME))
|
||||
{
|
||||
if (__bind_next (&dbp) == NIS_SUCCESS)
|
||||
if (__nisbind_next (dbp) == NIS_SUCCESS)
|
||||
{
|
||||
while (__bind_connect (&dbp) != NIS_SUCCESS)
|
||||
while (__nisbind_connect (dbp) != NIS_SUCCESS)
|
||||
{
|
||||
if (__bind_next (&dbp) != NIS_SUCCESS)
|
||||
{
|
||||
__bind_destroy (&dbp);
|
||||
if (__nisbind_next (dbp) != NIS_SUCCESS)
|
||||
return NIS_SUCCESS;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
|
@ -299,19 +275,16 @@ __do_niscall2 (const nis_server *server, u_int server_len, u_long prog,
|
|||
}
|
||||
break;
|
||||
case NIS_FINDDIRECTORY:
|
||||
if ((((fd_result *)resp)->status == NIS_NOTFOUND) ||
|
||||
if ((((fd_result *)resp)->status == NIS_SYSTEMERROR) ||
|
||||
(((fd_result *)resp)->status == NIS_NOSUCHNAME) ||
|
||||
(((fd_result *)resp)->status == NIS_NOT_ME))
|
||||
{
|
||||
if (__bind_next (&dbp) == NIS_SUCCESS)
|
||||
if (__nisbind_next (dbp) == NIS_SUCCESS)
|
||||
{
|
||||
while (__bind_connect (&dbp) != NIS_SUCCESS)
|
||||
while (__nisbind_connect (dbp) != NIS_SUCCESS)
|
||||
{
|
||||
if (__bind_next (&dbp) != NIS_SUCCESS)
|
||||
{
|
||||
__bind_destroy (&dbp);
|
||||
return NIS_SUCCESS;
|
||||
}
|
||||
if (__nisbind_next (dbp) != NIS_SUCCESS)
|
||||
return NIS_SUCCESS;
|
||||
}
|
||||
}
|
||||
else
|
||||
|
@ -321,19 +294,16 @@ __do_niscall2 (const nis_server *server, u_int server_len, u_long prog,
|
|||
break;
|
||||
case NIS_DUMPLOG: /* log_result */
|
||||
case NIS_DUMP:
|
||||
if ((((log_result *)resp)->lr_status == NIS_NOTFOUND) ||
|
||||
if ((((log_result *)resp)->lr_status == NIS_SYSTEMERROR) ||
|
||||
(((log_result *)resp)->lr_status == NIS_NOSUCHNAME) ||
|
||||
(((log_result *)resp)->lr_status == NIS_NOT_ME))
|
||||
{
|
||||
if (__bind_next (&dbp) == NIS_SUCCESS)
|
||||
if (__nisbind_next (dbp) == NIS_SUCCESS)
|
||||
{
|
||||
while (__bind_connect (&dbp) != NIS_SUCCESS)
|
||||
while (__nisbind_connect (dbp) != NIS_SUCCESS)
|
||||
{
|
||||
if (__bind_next (&dbp) != NIS_SUCCESS)
|
||||
{
|
||||
__bind_destroy (&dbp);
|
||||
return NIS_SUCCESS;
|
||||
}
|
||||
if (__nisbind_next (dbp) != NIS_SUCCESS)
|
||||
return NIS_SUCCESS;
|
||||
}
|
||||
}
|
||||
else
|
||||
|
@ -344,7 +314,6 @@ __do_niscall2 (const nis_server *server, u_int server_len, u_long prog,
|
|||
default:
|
||||
break;
|
||||
}
|
||||
__bind_destroy (&dbp);
|
||||
retcode = NIS_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
@ -353,9 +322,37 @@ __do_niscall2 (const nis_server *server, u_int server_len, u_long prog,
|
|||
return retcode;
|
||||
}
|
||||
|
||||
nis_error
|
||||
__do_niscall2 (const nis_server *server, u_int server_len, u_long prog,
|
||||
xdrproc_t xargs, caddr_t req, xdrproc_t xres, caddr_t resp,
|
||||
u_long flags, nis_cb *cb)
|
||||
{
|
||||
dir_binding dbp;
|
||||
nis_error status;
|
||||
|
||||
if (flags & MASTER_ONLY)
|
||||
server_len = 1;
|
||||
|
||||
status = __nisbind_create (&dbp, server, server_len, flags);
|
||||
if (status != NIS_SUCCESS)
|
||||
return status;
|
||||
|
||||
while (__nisbind_connect (&dbp) != NIS_SUCCESS)
|
||||
{
|
||||
if (__nisbind_next (&dbp) != NIS_SUCCESS)
|
||||
return NIS_NAMEUNREACHABLE;
|
||||
}
|
||||
|
||||
status = __do_niscall3 (&dbp, prog, xargs, req, xres, resp, flags, cb);
|
||||
|
||||
__nisbind_destroy (&dbp);
|
||||
|
||||
return status;
|
||||
|
||||
}
|
||||
|
||||
static directory_obj *
|
||||
rec_dirsearch (const_nis_name name, directory_obj *dir, u_long flags,
|
||||
nis_error *status)
|
||||
rec_dirsearch (const_nis_name name, directory_obj *dir, nis_error *status)
|
||||
{
|
||||
fd_result *fd_res;
|
||||
XDR xdrs;
|
||||
|
@ -396,7 +393,7 @@ rec_dirsearch (const_nis_name name, directory_obj *dir, u_long flags,
|
|||
/* We have found a NIS+ server serving ndomain, now
|
||||
let us search for "name" */
|
||||
nis_free_directory (dir);
|
||||
return rec_dirsearch (name, obj, flags, status);
|
||||
return rec_dirsearch (name, obj, status);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -461,7 +458,7 @@ rec_dirsearch (const_nis_name name, directory_obj *dir, u_long flags,
|
|||
/* We have found a NIS+ server serving ndomain, now
|
||||
let us search for "name" */
|
||||
nis_free_directory (dir);
|
||||
return rec_dirsearch (name, obj, flags, status);
|
||||
return rec_dirsearch (name, obj, status);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
@ -478,7 +475,7 @@ rec_dirsearch (const_nis_name name, directory_obj *dir, u_long flags,
|
|||
/* We try to query the current server for the searched object,
|
||||
maybe he know about it ? */
|
||||
static directory_obj *
|
||||
first_shoot (const_nis_name name, directory_obj *dir, u_long flags)
|
||||
first_shoot (const_nis_name name, directory_obj *dir)
|
||||
{
|
||||
directory_obj *obj;
|
||||
fd_result *fd_res;
|
||||
|
@ -515,51 +512,57 @@ first_shoot (const_nis_name name, directory_obj *dir, u_long flags)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
nis_error
|
||||
__nisfind_server (const_nis_name name, directory_obj **dir)
|
||||
{
|
||||
if (name == NULL)
|
||||
return NIS_BADNAME;
|
||||
|
||||
#if 0
|
||||
/* Search in local cache. In the moment, we ignore the fastest server */
|
||||
if (!(flags & NO_CACHE))
|
||||
dir = __nis_cache_search (name, flags, &cinfo);
|
||||
#endif
|
||||
|
||||
if (*dir == NULL)
|
||||
{
|
||||
nis_error status;
|
||||
directory_obj *obj;
|
||||
|
||||
*dir = readColdStartFile ();
|
||||
if (*dir == NULL) /* No /var/nis/NIS_COLD_START->no NIS+ installed */
|
||||
return NIS_UNAVAIL;
|
||||
|
||||
/* Try at first, if servers in "dir" know our object */
|
||||
obj = first_shoot (name, *dir);
|
||||
if (obj == NULL)
|
||||
{
|
||||
*dir = rec_dirsearch (name, *dir, &status);
|
||||
if (*dir == NULL)
|
||||
return status;
|
||||
}
|
||||
else
|
||||
*dir = obj;
|
||||
}
|
||||
|
||||
return NIS_SUCCESS;
|
||||
}
|
||||
|
||||
nis_error
|
||||
__do_niscall (const_nis_name name, u_long prog, xdrproc_t xargs,
|
||||
caddr_t req, xdrproc_t xres, caddr_t resp, u_long flags,
|
||||
nis_cb *cb)
|
||||
{
|
||||
nis_error retcode;
|
||||
dir_binding bptr;
|
||||
directory_obj *dir = NULL;
|
||||
nis_server *server;
|
||||
u_int server_len;
|
||||
cache2_info cinfo = {-1, -1, -1};
|
||||
int saved_errno = errno;
|
||||
|
||||
if (name == NULL)
|
||||
return NIS_BADNAME;
|
||||
|
||||
/* Search in local cache. In the moment, we ignore the fastest server */
|
||||
if (!(flags & NO_CACHE))
|
||||
dir = __nis_cache_search (name, flags, &cinfo);
|
||||
|
||||
if (dir == NULL)
|
||||
{
|
||||
nis_error status;
|
||||
directory_obj *obj;
|
||||
|
||||
dir = readColdStartFile ();
|
||||
if (dir == NULL) /* No /var/nis/NIS_COLD_START->no NIS+ installed */
|
||||
{
|
||||
__set_errno (saved_errno);
|
||||
return NIS_UNAVAIL;
|
||||
}
|
||||
|
||||
/* Try at first, if servers in "dir" know our object */
|
||||
obj = first_shoot (name, dir, flags);
|
||||
if (obj == NULL)
|
||||
{
|
||||
dir = rec_dirsearch (name, dir, flags, &status);
|
||||
if (dir == NULL)
|
||||
{
|
||||
__set_errno (saved_errno);
|
||||
return status;
|
||||
}
|
||||
}
|
||||
else
|
||||
dir = obj;
|
||||
}
|
||||
retcode = __nisfind_server (name, &dir);
|
||||
if (retcode != NIS_SUCCESS)
|
||||
return retcode;
|
||||
|
||||
if (flags & MASTER_ONLY)
|
||||
{
|
||||
|
@ -572,9 +575,22 @@ __do_niscall (const_nis_name name, u_long prog, xdrproc_t xargs,
|
|||
server_len = dir->do_servers.do_servers_len;
|
||||
}
|
||||
|
||||
retcode = __nisbind_create (&bptr, server, server_len, flags);
|
||||
if (retcode == NIS_SUCCESS)
|
||||
{
|
||||
while (__nisbind_connect (&bptr) != NIS_SUCCESS)
|
||||
{
|
||||
if (__nisbind_next (&bptr) != NIS_SUCCESS)
|
||||
{
|
||||
nis_free_directory (dir);
|
||||
__nisbind_destroy (&bptr);
|
||||
return NIS_NAMEUNREACHABLE;
|
||||
}
|
||||
}
|
||||
retcode = __do_niscall3 (&bptr, prog, xargs, req, xres, resp, flags, cb);
|
||||
|
||||
retcode = __do_niscall2 (server, server_len, prog, xargs, req, xres, resp,
|
||||
flags, cb, &cinfo);
|
||||
__nisbind_destroy (&bptr);
|
||||
}
|
||||
|
||||
nis_free_directory (dir);
|
||||
|
||||
|
|
|
@ -58,7 +58,7 @@ nis_checkpoint(const_nis_name dirname)
|
|||
if (__do_niscall2 (&NIS_RES_OBJECT(res2)->DI_data.do_servers.do_servers_val[i],
|
||||
1, NIS_CHECKPOINT, (xdrproc_t) _xdr_nis_name,
|
||||
(caddr_t) &dirname, (xdrproc_t) _xdr_cp_result,
|
||||
(caddr_t) &cpres, 0, NULL, NULL) != NIS_SUCCESS)
|
||||
(caddr_t) &cpres, 0, NULL) != NIS_SUCCESS)
|
||||
NIS_RES_STATUS (res) = NIS_RPCERROR;
|
||||
else
|
||||
{
|
||||
|
|
|
@ -31,18 +31,26 @@ readColdStartFile (void)
|
|||
XDR xdrs;
|
||||
FILE *in;
|
||||
bool_t status;
|
||||
directory_obj obj;
|
||||
directory_obj *obj = calloc (1, sizeof (directory_obj));
|
||||
|
||||
if (obj == NULL)
|
||||
return NULL;
|
||||
|
||||
in = fopen (cold_start_file, "rb");
|
||||
if (in == NULL)
|
||||
return NULL;
|
||||
memset (&obj, '\0', sizeof (obj));
|
||||
xdrstdio_create (&xdrs, in, XDR_DECODE);
|
||||
status = _xdr_directory_obj (&xdrs, &obj);
|
||||
status = _xdr_directory_obj (&xdrs, obj);
|
||||
xdr_destroy (&xdrs);
|
||||
fclose (in);
|
||||
|
||||
return status ? nis_clone_directory (&obj, NULL) : NULL;
|
||||
if (status)
|
||||
return obj;
|
||||
else
|
||||
{
|
||||
nis_free_directory (obj);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
bool_t
|
||||
|
@ -70,19 +78,27 @@ nis_read_obj (const char *name)
|
|||
XDR xdrs;
|
||||
FILE *in;
|
||||
bool_t status;
|
||||
nis_object obj;
|
||||
nis_object *obj = calloc (1, sizeof (nis_object));
|
||||
|
||||
if (obj == NULL)
|
||||
return NULL;
|
||||
|
||||
in = fopen (name, "rb");
|
||||
if (in == NULL)
|
||||
return NULL;
|
||||
|
||||
memset (&obj, '\0', sizeof (obj));
|
||||
xdrstdio_create (&xdrs, in, XDR_DECODE);
|
||||
status =_xdr_nis_object (&xdrs, &obj);
|
||||
status =_xdr_nis_object (&xdrs, obj);
|
||||
xdr_destroy (&xdrs);
|
||||
fclose (in);
|
||||
|
||||
return status ? nis_clone_object (&obj, NULL) : NULL;
|
||||
if (status)
|
||||
return obj;
|
||||
else
|
||||
{
|
||||
nis_free_object (obj);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
bool_t
|
||||
|
|
|
@ -110,8 +110,25 @@ struct findserv_req
|
|||
};
|
||||
|
||||
long
|
||||
__nis_findfastest (dir_binding * bind)
|
||||
__nis_findfastest (dir_binding *bind)
|
||||
{
|
||||
#if 0
|
||||
unsigned long i, j;
|
||||
|
||||
for (i = 0; i < bind->server_len; i++)
|
||||
for (j = 0; j < bind->server_val[i].ep.ep_len; ++j)
|
||||
if (strcmp (bind->server_val[i].ep.ep_val[j].family, "inet") == 0)
|
||||
if ((bind->server_val[i].ep.ep_val[j].proto == NULL) ||
|
||||
(bind->server_val[i].ep.ep_val[j].proto[0] == '-') ||
|
||||
(bind->server_val[i].ep.ep_val[j].proto[0] == '\0'))
|
||||
{
|
||||
bind->server_used = i;
|
||||
bind->current_ep = j;
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
#else
|
||||
const struct timeval TIMEOUT50 = {5, 0};
|
||||
const struct timeval TIMEOUT00 = {0, 0};
|
||||
struct findserv_req **pings;
|
||||
|
@ -137,7 +154,7 @@ __nis_findfastest (dir_binding * bind)
|
|||
for (j = 0; j < bind->server_val[i].ep.ep_len; ++j)
|
||||
if (strcmp (bind->server_val[i].ep.ep_val[j].family, "inet") == 0)
|
||||
if ((bind->server_val[i].ep.ep_val[j].proto == NULL) ||
|
||||
(strcmp (bind->server_val[i].ep.ep_val[j].proto, "-") == 0) ||
|
||||
(bind->server_val[i].ep.ep_val[j].proto[0] == '-') ||
|
||||
(bind->server_val[i].ep.ep_val[j].proto[0] == '\0'))
|
||||
{
|
||||
sin.sin_addr.s_addr =
|
||||
|
@ -228,4 +245,5 @@ __nis_findfastest (dir_binding * bind)
|
|||
free (pings);
|
||||
|
||||
return found;
|
||||
#endif
|
||||
}
|
||||
|
|
|
@ -24,31 +24,6 @@
|
|||
|
||||
__BEGIN_DECLS
|
||||
|
||||
struct dir_binding
|
||||
{
|
||||
CLIENT *clnt; /* RPC CLIENT handle */
|
||||
nis_server *server_val; /* List of servers */
|
||||
u_int server_len; /* # of servers */
|
||||
u_int server_used; /* Which server we are bind in the moment ? */
|
||||
u_int current_ep; /* Which endpoint of the server are in use? */
|
||||
u_int trys; /* How many server have we tried ? */
|
||||
u_int class; /* From which class is server_val ? */
|
||||
bool_t master_only; /* Is only binded to the master */
|
||||
bool_t use_auth; /* Do we use AUTH ? */
|
||||
bool_t use_udp; /* Do we use UDP ? */
|
||||
struct sockaddr_in addr; /* Server's IP address */
|
||||
int socket; /* Server's local socket */
|
||||
};
|
||||
typedef struct dir_binding dir_binding;
|
||||
|
||||
struct cache2_info
|
||||
{
|
||||
long server_used;
|
||||
long current_ep;
|
||||
long class;
|
||||
};
|
||||
typedef struct cache2_info cache2_info;
|
||||
|
||||
struct nis_cb
|
||||
{
|
||||
nis_server *serv;
|
||||
|
@ -66,8 +41,7 @@ extern long __nis_findfastest __P ((dir_binding *bind));
|
|||
extern nis_error __do_niscall2 __P ((const nis_server *serv, u_int serv_len,
|
||||
u_long prog, xdrproc_t xargs, caddr_t req,
|
||||
xdrproc_t xres, caddr_t resp,
|
||||
u_long flags, nis_cb *cb,
|
||||
cache2_info *cinfo));
|
||||
u_long flags, nis_cb *cb));
|
||||
extern nis_error __do_niscall __P ((const_nis_name name, u_long prog,
|
||||
xdrproc_t xargs, caddr_t req,
|
||||
xdrproc_t xres, caddr_t resp,
|
||||
|
@ -81,13 +55,6 @@ extern struct nis_cb *__nis_create_callback
|
|||
const void *userdata, u_long flags));
|
||||
extern nis_error __nis_destroy_callback __P ((struct nis_cb *cb));
|
||||
|
||||
#ifdef _LIBC
|
||||
/* NIS+ Cache functions */
|
||||
extern directory_obj *__nis_cache_search __P ((const_nis_name name,
|
||||
u_long flags,
|
||||
cache2_info *cinfo));
|
||||
#endif
|
||||
|
||||
__END_DECLS
|
||||
|
||||
#endif
|
||||
|
|
166
nis/nis_lookup.c
166
nis/nis_lookup.c
|
@ -25,20 +25,20 @@
|
|||
nis_result *
|
||||
nis_lookup (const_nis_name name, const u_long flags)
|
||||
{
|
||||
nis_result *res;
|
||||
nis_result *res = calloc (1, sizeof (nis_result));
|
||||
struct ns_request req;
|
||||
nis_name *names;
|
||||
nis_error status;
|
||||
int link_first_try = 0;
|
||||
int count_links = 0; /* We will follow only 16 links in the deep */
|
||||
int done = 0;
|
||||
int name_nr = 0;
|
||||
nis_name namebuf[2] = {NULL, NULL};
|
||||
|
||||
res = calloc (1, sizeof (nis_result));
|
||||
if (res == NULL)
|
||||
return NULL;
|
||||
|
||||
if (flags & EXPAND_NAME)
|
||||
if ((flags & EXPAND_NAME) && (name[strlen (name) - 1] != '.'))
|
||||
{
|
||||
names = nis_getnames (name);
|
||||
if (names == NULL)
|
||||
|
@ -56,51 +56,141 @@ nis_lookup (const_nis_name name, const u_long flags)
|
|||
req.ns_name = names[0];
|
||||
while (!done)
|
||||
{
|
||||
dir_binding bptr;
|
||||
directory_obj *dir = NULL;
|
||||
req.ns_object.ns_object_len = 0;
|
||||
req.ns_object.ns_object_val = NULL;
|
||||
memset (res, '\0', sizeof (nis_result));
|
||||
|
||||
status = __do_niscall (req.ns_name, NIS_LOOKUP,
|
||||
(xdrproc_t) _xdr_ns_request,
|
||||
(caddr_t) & req,
|
||||
(xdrproc_t) _xdr_nis_result,
|
||||
(caddr_t) res, flags, NULL);
|
||||
status = __nisfind_server (req.ns_name, &dir);
|
||||
if (status != NIS_SUCCESS)
|
||||
NIS_RES_STATUS (res) = status;
|
||||
{
|
||||
NIS_RES_STATUS (res) = status;
|
||||
return res;
|
||||
}
|
||||
|
||||
status = __nisbind_create (&bptr, dir->do_servers.do_servers_val,
|
||||
dir->do_servers.do_servers_len, flags);
|
||||
if (status != NIS_SUCCESS)
|
||||
{
|
||||
NIS_RES_STATUS (res) = status;
|
||||
nis_free_directory (dir);
|
||||
return res;
|
||||
}
|
||||
|
||||
while (__nisbind_connect (&bptr) != NIS_SUCCESS)
|
||||
{
|
||||
if (__nisbind_next (&bptr) != NIS_SUCCESS)
|
||||
{
|
||||
__nisbind_destroy (&bptr);
|
||||
nis_free_directory (dir);
|
||||
NIS_RES_STATUS (res) = NIS_NAMEUNREACHABLE;
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
do
|
||||
{
|
||||
static struct timeval RPCTIMEOUT = {10, 0};
|
||||
enum clnt_stat result;
|
||||
|
||||
again:
|
||||
result = clnt_call (bptr.clnt, NIS_LOOKUP,
|
||||
(xdrproc_t) _xdr_ns_request,
|
||||
(caddr_t) &req, (xdrproc_t) _xdr_nis_result,
|
||||
(caddr_t) res, RPCTIMEOUT);
|
||||
|
||||
if (result != RPC_SUCCESS)
|
||||
status = NIS_RPCERROR;
|
||||
else
|
||||
{
|
||||
if (NIS_RES_STATUS (res) == NIS_SUCCESS)
|
||||
{
|
||||
if (__type_of(NIS_RES_OBJECT (res)) == NIS_LINK_OBJ &&
|
||||
flags & FOLLOW_LINKS) /* We are following links */
|
||||
{
|
||||
if (count_links)
|
||||
free (req.ns_name);
|
||||
/* if we hit the link limit, bail */
|
||||
if (count_links > NIS_MAXLINKS)
|
||||
{
|
||||
NIS_RES_STATUS (res) = NIS_LINKNAMEERROR;
|
||||
break;
|
||||
}
|
||||
++count_links;
|
||||
req.ns_name =
|
||||
strdup (NIS_RES_OBJECT (res)->LI_data.li_name);
|
||||
nis_freeresult (res);
|
||||
res = calloc (1, sizeof (nis_result));
|
||||
if (res == NULL)
|
||||
{
|
||||
__nisbind_destroy (&bptr);
|
||||
nis_free_directory (dir);
|
||||
return NULL;
|
||||
}
|
||||
link_first_try = 1; /* Try at first the old binding */
|
||||
goto again;
|
||||
}
|
||||
}
|
||||
else
|
||||
if ((NIS_RES_STATUS (res) == NIS_SYSTEMERROR) ||
|
||||
(NIS_RES_STATUS (res) == NIS_NOSUCHNAME) ||
|
||||
(NIS_RES_STATUS (res) == NIS_NOT_ME))
|
||||
{
|
||||
if (link_first_try)
|
||||
{
|
||||
__nisbind_destroy (&bptr);
|
||||
nis_free_directory (dir);
|
||||
|
||||
if (__nisfind_server (req.ns_name, &dir) != NIS_SUCCESS)
|
||||
return res;
|
||||
|
||||
if (__nisbind_create (&bptr,
|
||||
dir->do_servers.do_servers_val,
|
||||
dir->do_servers.do_servers_len,
|
||||
flags) != NIS_SUCCESS)
|
||||
{
|
||||
nis_free_directory (dir);
|
||||
return res;
|
||||
}
|
||||
}
|
||||
else
|
||||
if (__nisbind_next (&bptr) != NIS_SUCCESS)
|
||||
break; /* No more servers to search */
|
||||
|
||||
while (__nisbind_connect (&bptr) != NIS_SUCCESS)
|
||||
{
|
||||
if (__nisbind_next (&bptr) != NIS_SUCCESS)
|
||||
{
|
||||
__nisbind_destroy (&bptr);
|
||||
nis_free_directory (dir);
|
||||
return res;
|
||||
}
|
||||
}
|
||||
goto again;
|
||||
}
|
||||
break;
|
||||
}
|
||||
link_first_try = 0; /* Set it back */
|
||||
status= NIS_SUCCESS;
|
||||
}
|
||||
while ((flags & HARD_LOOKUP) && status == NIS_RPCERROR);
|
||||
|
||||
__nisbind_destroy (&bptr);
|
||||
nis_free_directory (dir);
|
||||
|
||||
if (status != NIS_SUCCESS)
|
||||
{
|
||||
NIS_RES_STATUS (res) = status;
|
||||
return res;
|
||||
}
|
||||
|
||||
switch (NIS_RES_STATUS (res))
|
||||
{
|
||||
case NIS_PARTIAL:
|
||||
case NIS_SUCCESS:
|
||||
case NIS_S_SUCCESS:
|
||||
if (__type_of(NIS_RES_OBJECT (res)) == NIS_LINK_OBJ &&
|
||||
flags & FOLLOW_LINKS) /* We are following links */
|
||||
{
|
||||
/* if we hit the link limit, bail */
|
||||
if (count_links > NIS_MAXLINKS)
|
||||
{
|
||||
NIS_RES_STATUS (res) = NIS_LINKNAMEERROR;
|
||||
++done;
|
||||
break;
|
||||
}
|
||||
if (count_links)
|
||||
free (req.ns_name);
|
||||
++count_links;
|
||||
req.ns_name = strdup (NIS_RES_OBJECT (res)->LI_data.li_name);
|
||||
nis_freeresult (res);
|
||||
res = calloc (1, sizeof (nis_result));
|
||||
if (res == NULL)
|
||||
return NULL;
|
||||
}
|
||||
else
|
||||
++done;
|
||||
break;
|
||||
case NIS_CBRESULTS:
|
||||
/* The callback is handled in __do_niscall2 */
|
||||
++done;
|
||||
break;
|
||||
case NIS_UNAVAIL:
|
||||
/* NIS+ is not installed, or all servers are down */
|
||||
case NIS_LINKNAMEERROR: /* We follow to max links */
|
||||
case NIS_UNAVAIL: /* NIS+ is not installed, or all servers are down */
|
||||
++done;
|
||||
break;
|
||||
default:
|
||||
|
|
|
@ -35,7 +35,7 @@ nis_mkdir (const_nis_name dir, const nis_server *server)
|
|||
res2 = __do_niscall2 (server, 1, NIS_MKDIR,
|
||||
(xdrproc_t) _xdr_nis_name,
|
||||
(caddr_t) &dir, (xdrproc_t) _xdr_nis_error,
|
||||
(caddr_t) &res, 0, NULL, NULL);
|
||||
(caddr_t) &res, 0, NULL);
|
||||
if (res2 != NIS_SUCCESS)
|
||||
return res2;
|
||||
|
||||
|
|
|
@ -62,7 +62,7 @@ nis_ping (const_nis_name dirname, u_long utime, const nis_object *dirobj)
|
|||
__do_niscall2 (&obj->DI_data.do_servers.do_servers_val[i], 1,
|
||||
NIS_PING, (xdrproc_t) _xdr_ping_args,
|
||||
(caddr_t) &args, (xdrproc_t) xdr_void,
|
||||
(caddr_t) NULL, 0, NULL, NULL);
|
||||
(caddr_t) NULL, 0, NULL);
|
||||
if (res)
|
||||
nis_freeresult (res);
|
||||
}
|
||||
|
|
|
@ -33,7 +33,7 @@ nis_rmdir (const_nis_name dir, const nis_server *server)
|
|||
res2 = __do_niscall2 (server, 1, NIS_RMDIR,
|
||||
(xdrproc_t) _xdr_nis_name,
|
||||
(caddr_t) &dir, (xdrproc_t) _xdr_nis_error,
|
||||
(caddr_t) &res, 0, NULL, NULL);
|
||||
(caddr_t) &res, 0, NULL);
|
||||
if (res2 != NIS_SUCCESS)
|
||||
return res2;
|
||||
|
||||
|
|
|
@ -41,7 +41,7 @@ nis_servstate (const nis_server *serv, const nis_tag *tags,
|
|||
|
||||
if (__do_niscall2 (serv, 1, NIS_SERVSTATE, (xdrproc_t) _xdr_nis_taglist,
|
||||
(caddr_t) &taglist, (xdrproc_t) _xdr_nis_taglist,
|
||||
(caddr_t) &tagres, 0, NULL, NULL) != RPC_SUCCESS)
|
||||
(caddr_t) &tagres, 0, NULL) != RPC_SUCCESS)
|
||||
return NIS_RPCERROR;
|
||||
|
||||
*result = tagres.tags.tags_val;
|
||||
|
@ -67,7 +67,7 @@ nis_stats (const nis_server *serv, const nis_tag *tags,
|
|||
|
||||
if (__do_niscall2 (serv, 1, NIS_STATUS, (xdrproc_t) _xdr_nis_taglist,
|
||||
(caddr_t) &taglist, (xdrproc_t) _xdr_nis_taglist,
|
||||
(caddr_t) &tagres, 0, NULL, NULL) != RPC_SUCCESS)
|
||||
(caddr_t) &tagres, 0, NULL) != RPC_SUCCESS)
|
||||
return NIS_RPCERROR;
|
||||
|
||||
*result = tagres.tags.tags_val;
|
||||
|
|
413
nis/nis_table.c
413
nis/nis_table.c
|
@ -110,6 +110,40 @@ __create_ib_request (const_nis_name name, u_long flags)
|
|||
return ibreq;
|
||||
}
|
||||
|
||||
static struct timeval RPCTIMEOUT = {10, 0};
|
||||
|
||||
static char *
|
||||
__get_tablepath (char *name, dir_binding *bptr)
|
||||
{
|
||||
enum clnt_stat result;
|
||||
nis_result *res = calloc (1, sizeof (nis_result));
|
||||
struct ns_request req;
|
||||
|
||||
if (res == NULL)
|
||||
return NULL;
|
||||
|
||||
req.ns_name = name;
|
||||
req.ns_object.ns_object_len = 0;
|
||||
req.ns_object.ns_object_val = NULL;
|
||||
|
||||
result = clnt_call (bptr->clnt, NIS_LOOKUP, (xdrproc_t) _xdr_ns_request,
|
||||
(caddr_t) &req, (xdrproc_t) _xdr_nis_result,
|
||||
(caddr_t) res, RPCTIMEOUT);
|
||||
|
||||
if (result == RPC_SUCCESS && NIS_RES_STATUS (res) == NIS_SUCCESS &&
|
||||
__type_of (NIS_RES_OBJECT (res)) == NIS_TABLE_OBJ)
|
||||
{
|
||||
char *cptr = strdup (NIS_RES_OBJECT (res)->TA_data.ta_path);
|
||||
nis_freeresult (res);
|
||||
return cptr;
|
||||
}
|
||||
else
|
||||
{
|
||||
nis_freeresult (res);
|
||||
return strdup ("");
|
||||
}
|
||||
}
|
||||
|
||||
nis_result *
|
||||
nis_list (const_nis_name name, u_long flags,
|
||||
int (*callback) (const_nis_name name,
|
||||
|
@ -120,12 +154,16 @@ nis_list (const_nis_name name, u_long flags,
|
|||
nis_result *res = NULL;
|
||||
ib_request *ibreq;
|
||||
int status;
|
||||
enum clnt_stat clnt_status;
|
||||
int count_links = 0; /* We will only follow NIS_MAXLINKS links! */
|
||||
int done = 0;
|
||||
nis_name *names;
|
||||
nis_name namebuf[2] = {NULL, NULL};
|
||||
int name_nr = 0;
|
||||
nis_cb *cb = NULL;
|
||||
char *tableptr, *tablepath = NULL;
|
||||
int have_tablepath = 0;
|
||||
int first_try = 0; /* Do we try the old binding at first ? */
|
||||
|
||||
res = calloc (1, sizeof (nis_result));
|
||||
if (res == NULL)
|
||||
|
@ -164,189 +202,230 @@ nis_list (const_nis_name name, u_long flags,
|
|||
|
||||
cb = NULL;
|
||||
|
||||
if (flags & FOLLOW_PATH || flags & ALL_RESULTS)
|
||||
while (!done)
|
||||
{
|
||||
nis_result *lres;
|
||||
u_long newflags = flags & ~FOLLOW_PATH & ~ALL_RESULTS;
|
||||
char table_path[NIS_MAXPATH + 3];
|
||||
char *ntable, *p;
|
||||
u_long done = 0, failures = 0;
|
||||
dir_binding bptr;
|
||||
directory_obj *dir = NULL;
|
||||
|
||||
while (names[name_nr] != NULL && !done)
|
||||
{
|
||||
lres = nis_lookup (names[name_nr], newflags | NO_AUTHINFO);
|
||||
if (lres == NULL || NIS_RES_STATUS (lres) != NIS_SUCCESS)
|
||||
{
|
||||
NIS_RES_STATUS (res) = NIS_RES_STATUS (lres);
|
||||
nis_freeresult (lres);
|
||||
++name_nr;
|
||||
continue;
|
||||
}
|
||||
memset (res, '\0', sizeof (nis_result));
|
||||
|
||||
/* nis_lookup handles FOLLOW_LINKS,
|
||||
so we must have a table object.*/
|
||||
if (__type_of (NIS_RES_OBJECT (lres)) != NIS_TABLE_OBJ)
|
||||
{
|
||||
nis_freeresult (lres);
|
||||
NIS_RES_STATUS (res) = NIS_INVALIDOBJ;
|
||||
break;
|
||||
}
|
||||
status = __nisfind_server (ibreq->ibr_name, &dir);
|
||||
if (status != NIS_SUCCESS)
|
||||
{
|
||||
NIS_RES_STATUS (res) = status;
|
||||
return res;
|
||||
}
|
||||
|
||||
/* Save the path, discard everything else. */
|
||||
p = __stpncpy (table_path, names[name_nr], NIS_MAXPATH);
|
||||
*p++ = ':';
|
||||
p = __stpncpy (p, NIS_RES_OBJECT (lres)->TA_data.ta_path,
|
||||
NIS_MAXPATH - (p - table_path));
|
||||
*p = '\0';
|
||||
nis_freeresult (lres);
|
||||
free (res);
|
||||
res = NULL;
|
||||
status = __nisbind_create (&bptr, dir->do_servers.do_servers_val,
|
||||
dir->do_servers.do_servers_len, flags);
|
||||
if (status != NIS_SUCCESS)
|
||||
{
|
||||
NIS_RES_STATUS (res) = status;
|
||||
nis_free_directory (dir);
|
||||
return res;
|
||||
}
|
||||
|
||||
p = table_path;
|
||||
while (__nisbind_connect (&bptr) != NIS_SUCCESS)
|
||||
if (__nisbind_next (&bptr) != NIS_SUCCESS)
|
||||
{
|
||||
__nisbind_destroy (&bptr);
|
||||
nis_free_directory (dir);
|
||||
NIS_RES_STATUS (res) = NIS_NAMEUNREACHABLE;
|
||||
return res;
|
||||
}
|
||||
|
||||
while (((ntable = strsep (&p, ":")) != NULL) && !done)
|
||||
{
|
||||
char *c;
|
||||
|
||||
if (res != NULL)
|
||||
nis_freeresult (res);
|
||||
|
||||
/* Do the job recursive here! */
|
||||
if ((c = strchr(name, ']')) != NULL)
|
||||
{
|
||||
/* Have indexed name ! */
|
||||
int index_len = c - name + 2;
|
||||
char buf[index_len + strlen (ntable) + 1];
|
||||
|
||||
c = __stpncpy (buf, name, index_len);
|
||||
strcpy (c, ntable);
|
||||
res = nis_list (buf, newflags, callback,userdata);
|
||||
}
|
||||
else
|
||||
res = nis_list (ntable, newflags, callback, userdata);
|
||||
if (res == NULL)
|
||||
return NULL;
|
||||
switch (NIS_RES_STATUS (res))
|
||||
{
|
||||
case NIS_SUCCESS:
|
||||
case NIS_CBRESULTS:
|
||||
if (!(flags & ALL_RESULTS))
|
||||
done = 1;
|
||||
break;
|
||||
case NIS_PARTIAL: /* The table is correct, we doesn't found
|
||||
the entry */
|
||||
break;
|
||||
default:
|
||||
if (flags & ALL_RESULTS)
|
||||
++failures;
|
||||
else
|
||||
done = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (NIS_RES_STATUS (res) == NIS_SUCCESS && failures)
|
||||
NIS_RES_STATUS (res) = NIS_S_SUCCESS;
|
||||
if (NIS_RES_STATUS (res) == NIS_NOTFOUND && failures)
|
||||
NIS_RES_STATUS (res) = NIS_S_NOTFOUND;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (callback != NULL)
|
||||
{
|
||||
cb = __nis_create_callback (callback, userdata, flags);
|
||||
ibreq->ibr_cbhost.ibr_cbhost_len = 1;
|
||||
ibreq->ibr_cbhost.ibr_cbhost_val = cb->serv;
|
||||
}
|
||||
|
||||
while (!done)
|
||||
{
|
||||
memset (res, '\0', sizeof (nis_result));
|
||||
|
||||
status = __do_niscall (ibreq->ibr_name, NIS_IBLIST,
|
||||
(xdrproc_t) _xdr_ib_request,
|
||||
(caddr_t) ibreq, (xdrproc_t) _xdr_nis_result,
|
||||
(caddr_t) res, flags, cb);
|
||||
if (status != NIS_SUCCESS)
|
||||
NIS_RES_STATUS (res) = status;
|
||||
|
||||
switch (NIS_RES_STATUS (res))
|
||||
{
|
||||
case NIS_PARTIAL:
|
||||
case NIS_SUCCESS:
|
||||
case NIS_S_SUCCESS:
|
||||
if (__type_of (NIS_RES_OBJECT (res)) == NIS_LINK_OBJ &&
|
||||
flags & FOLLOW_LINKS) /* We are following links. */
|
||||
{
|
||||
/* If we hit the link limit, bail. */
|
||||
if (count_links > NIS_MAXLINKS)
|
||||
{
|
||||
NIS_RES_STATUS (res) = NIS_LINKNAMEERROR;
|
||||
++done;
|
||||
break;
|
||||
}
|
||||
if (count_links)
|
||||
free (ibreq->ibr_name);
|
||||
++count_links;
|
||||
free (ibreq->ibr_name);
|
||||
ibreq->ibr_name =
|
||||
strdup (NIS_RES_OBJECT (res)->LI_data.li_name);
|
||||
if (NIS_RES_OBJECT (res)->LI_data.li_attrs.li_attrs_len)
|
||||
if (ibreq->ibr_srch.ibr_srch_len == 0)
|
||||
{
|
||||
ibreq->ibr_srch.ibr_srch_len =
|
||||
NIS_RES_OBJECT (res)->LI_data.li_attrs.li_attrs_len;
|
||||
ibreq->ibr_srch.ibr_srch_val =
|
||||
NIS_RES_OBJECT (res)->LI_data.li_attrs.li_attrs_val;
|
||||
}
|
||||
nis_freeresult (res);
|
||||
res = calloc (1, sizeof (nis_result));
|
||||
}
|
||||
else
|
||||
++done;
|
||||
break;
|
||||
case NIS_CBRESULTS:
|
||||
/* Calback is handled in nis_call.c (__do_niscall2),
|
||||
but we have to change the error code */
|
||||
NIS_RES_STATUS (res) = cb->result;
|
||||
++done;
|
||||
break;
|
||||
case NIS_UNAVAIL:
|
||||
/* NIS+ is not installed, or all servers are down. */
|
||||
++done;
|
||||
break;
|
||||
default:
|
||||
/* Try the next domainname if we don't follow a link. */
|
||||
if (count_links)
|
||||
{
|
||||
free (ibreq->ibr_name);
|
||||
NIS_RES_STATUS (res) = NIS_LINKNAMEERROR;
|
||||
++done;
|
||||
break;
|
||||
}
|
||||
++name_nr;
|
||||
if (names[name_nr] == NULL)
|
||||
{
|
||||
++done;
|
||||
break;
|
||||
}
|
||||
ibreq->ibr_name = names[name_nr];
|
||||
break;
|
||||
}
|
||||
}
|
||||
} /* End of not FOLLOW_PATH. */
|
||||
|
||||
again:
|
||||
clnt_status = clnt_call (bptr.clnt, NIS_IBLIST,
|
||||
(xdrproc_t) _xdr_ib_request, (caddr_t) ibreq,
|
||||
(xdrproc_t) _xdr_nis_result,
|
||||
(caddr_t) res, RPCTIMEOUT);
|
||||
|
||||
if (clnt_status != RPC_SUCCESS)
|
||||
NIS_RES_STATUS (res) = NIS_RPCERROR;
|
||||
else
|
||||
switch (NIS_RES_STATUS (res))
|
||||
{ /* start switch */
|
||||
case NIS_PARTIAL:
|
||||
case NIS_SUCCESS:
|
||||
case NIS_S_SUCCESS:
|
||||
if (__type_of (NIS_RES_OBJECT (res)) == NIS_LINK_OBJ &&
|
||||
flags & FOLLOW_LINKS) /* We are following links. */
|
||||
{
|
||||
free (ibreq->ibr_name);
|
||||
/* If we hit the link limit, bail. */
|
||||
if (count_links > NIS_MAXLINKS)
|
||||
{
|
||||
NIS_RES_STATUS (res) = NIS_LINKNAMEERROR;
|
||||
++done;
|
||||
break;
|
||||
}
|
||||
++count_links;
|
||||
ibreq->ibr_name =
|
||||
strdup (NIS_RES_OBJECT (res)->LI_data.li_name);
|
||||
if (NIS_RES_OBJECT (res)->LI_data.li_attrs.li_attrs_len)
|
||||
if (ibreq->ibr_srch.ibr_srch_len == 0)
|
||||
{
|
||||
ibreq->ibr_srch.ibr_srch_len =
|
||||
NIS_RES_OBJECT (res)->LI_data.li_attrs.li_attrs_len;
|
||||
ibreq->ibr_srch.ibr_srch_val =
|
||||
NIS_RES_OBJECT (res)->LI_data.li_attrs.li_attrs_val;
|
||||
}
|
||||
nis_freeresult (res);
|
||||
res = calloc (1, sizeof (nis_result));
|
||||
if (res == NULL)
|
||||
{
|
||||
if (have_tablepath)
|
||||
free (tablepath);
|
||||
__nisbind_destroy (&bptr);
|
||||
nis_free_directory (dir);
|
||||
return NULL;
|
||||
}
|
||||
first_try = 1; /* Try at first the old binding */
|
||||
goto again;
|
||||
}
|
||||
else if ((flags & FOLLOW_PATH) &&
|
||||
NIS_RES_STATUS (res) == NIS_PARTIAL)
|
||||
{
|
||||
if (!have_tablepath)
|
||||
{
|
||||
tablepath = __get_tablepath (ibreq->ibr_name, &bptr);
|
||||
tableptr = tablepath;
|
||||
have_tablepath = 1;
|
||||
}
|
||||
if (tableptr == NULL)
|
||||
{
|
||||
++done;
|
||||
break;
|
||||
}
|
||||
free (ibreq->ibr_name);
|
||||
ibreq->ibr_name = strsep (&tableptr, ":");
|
||||
if (ibreq->ibr_name == NULL || ibreq->ibr_name[0] == '\0')
|
||||
{
|
||||
ibreq->ibr_name = strdup ("");
|
||||
++done;
|
||||
}
|
||||
else
|
||||
{
|
||||
ibreq->ibr_name = strdup (ibreq->ibr_name);
|
||||
nis_freeresult (res);
|
||||
res = calloc (1, sizeof (nis_result));
|
||||
if (res == NULL)
|
||||
{
|
||||
if (have_tablepath)
|
||||
free (tablepath);
|
||||
__nisbind_destroy (&bptr);
|
||||
nis_free_directory (dir);
|
||||
return NULL;
|
||||
}
|
||||
first_try = 1;
|
||||
goto again;
|
||||
}
|
||||
}
|
||||
else
|
||||
++done;
|
||||
break;
|
||||
case NIS_CBRESULTS:
|
||||
if (cb != NULL)
|
||||
{
|
||||
__nis_do_callback (&bptr, &res->cookie, cb);
|
||||
NIS_RES_STATUS (res) = cb->result;
|
||||
|
||||
if (!(flags & ALL_RESULTS))
|
||||
++done;
|
||||
else
|
||||
{
|
||||
if (!have_tablepath)
|
||||
{
|
||||
tablepath = __get_tablepath (ibreq->ibr_name, &bptr);
|
||||
tableptr = tablepath;
|
||||
have_tablepath = 1;
|
||||
}
|
||||
if (tableptr == NULL)
|
||||
{
|
||||
++done;
|
||||
break;
|
||||
}
|
||||
free (ibreq->ibr_name);
|
||||
ibreq->ibr_name = strsep (&tableptr, ":");
|
||||
if (ibreq->ibr_name == NULL || ibreq->ibr_name[0] == '\0')
|
||||
{
|
||||
ibreq->ibr_name = strdup ("");
|
||||
++done;
|
||||
}
|
||||
else
|
||||
ibreq->ibr_name = strdup (ibreq->ibr_name);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case NIS_SYSTEMERROR:
|
||||
case NIS_NOSUCHNAME:
|
||||
case NIS_NOT_ME:
|
||||
/* If we had first tried the old binding, do nothing, but
|
||||
get a new binding */
|
||||
if (!first_try)
|
||||
{
|
||||
if (__nisbind_next (&bptr) != NIS_SUCCESS)
|
||||
{
|
||||
++done;
|
||||
break; /* No more servers to search */
|
||||
}
|
||||
while (__nisbind_connect (&bptr) != NIS_SUCCESS)
|
||||
{
|
||||
if (__nisbind_next (&bptr) != NIS_SUCCESS)
|
||||
{
|
||||
++done;
|
||||
break; /* No more servers to search */
|
||||
}
|
||||
}
|
||||
goto again;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
if (!first_try)
|
||||
{
|
||||
/* Try the next domainname if we don't follow a link. */
|
||||
if (count_links)
|
||||
{
|
||||
free (ibreq->ibr_name);
|
||||
NIS_RES_STATUS (res) = NIS_LINKNAMEERROR;
|
||||
++done;
|
||||
break;
|
||||
}
|
||||
++name_nr;
|
||||
if (names[name_nr] == NULL)
|
||||
{
|
||||
++done;
|
||||
break;
|
||||
}
|
||||
ibreq->ibr_name = names[name_nr];
|
||||
first_try = 1; /* Try old binding at first */
|
||||
goto again;
|
||||
}
|
||||
break;
|
||||
}
|
||||
first_try = 0;
|
||||
|
||||
if (cb)
|
||||
{
|
||||
__nis_destroy_callback (cb);
|
||||
ibreq->ibr_cbhost.ibr_cbhost_len = 0;
|
||||
ibreq->ibr_cbhost.ibr_cbhost_val = NULL;
|
||||
}
|
||||
|
||||
__nisbind_destroy (&bptr);
|
||||
nis_free_directory (dir);
|
||||
}
|
||||
|
||||
if (names != namebuf)
|
||||
nis_freenames (names);
|
||||
|
||||
if (cb)
|
||||
{
|
||||
__nis_destroy_callback (cb);
|
||||
ibreq->ibr_cbhost.ibr_cbhost_len = 0;
|
||||
ibreq->ibr_cbhost.ibr_cbhost_val = NULL;
|
||||
}
|
||||
|
||||
nis_free_request (ibreq);
|
||||
|
||||
return res;
|
||||
|
|
|
@ -38,7 +38,7 @@ __nis_finddirectory (directory_obj *dir, const_nis_name name)
|
|||
dir->do_servers.do_servers_len,
|
||||
NIS_FINDDIRECTORY, (xdrproc_t) _xdr_fd_args,
|
||||
(caddr_t) &fd_args, (xdrproc_t) _xdr_fd_result,
|
||||
(caddr_t) fd_res, NO_AUTHINFO|USE_DGRAM, NULL, NULL);
|
||||
(caddr_t) fd_res, NO_AUTHINFO|USE_DGRAM, NULL);
|
||||
if (status != NIS_SUCCESS)
|
||||
fd_res->status = status;
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* Copyright (C) 1997 Free Software Foundation, Inc.
|
||||
/* Copyright (C) 1997, 1998 Free Software Foundation, Inc.
|
||||
This file is part of the GNU C Library.
|
||||
Contributed by Thorsten Kukuk <kukuk@vt.uni-paderborn.de>, 1997.
|
||||
|
||||
|
@ -247,6 +247,35 @@ extern u_long __nis_hash __P ((const void *keyarg, register size_t len));
|
|||
extern int __nis_lock_cache __P ((void));
|
||||
extern int __nis_unlock_cache __P ((void));
|
||||
|
||||
/* (XXX INTERNAL FUNCTIONS, ONLY FOR rpc.nisd AND glibc !!) */
|
||||
#if defined (NIS_INTERNAL) || defined (_LIBC)
|
||||
|
||||
struct dir_binding
|
||||
{
|
||||
CLIENT *clnt; /* RPC CLIENT handle */
|
||||
nis_server *server_val; /* List of servers */
|
||||
u_int server_len; /* # of servers */
|
||||
u_int server_used; /* Which server we are bind in the moment ? */
|
||||
u_int current_ep; /* Which endpoint of the server are in use? */
|
||||
u_int trys; /* How many server have we tried ? */
|
||||
u_int class; /* From which class is server_val ? */
|
||||
bool_t master_only; /* Is only binded to the master */
|
||||
bool_t use_auth; /* Do we use AUTH ? */
|
||||
bool_t use_udp; /* Do we use UDP ? */
|
||||
struct sockaddr_in addr; /* Server's IP address */
|
||||
int socket; /* Server's local socket */
|
||||
};
|
||||
typedef struct dir_binding dir_binding;
|
||||
|
||||
extern nis_error __nisbind_create __P ((dir_binding *, const nis_server *,
|
||||
u_int, u_long));
|
||||
extern nis_error __nisbind_connect __P ((dir_binding *));
|
||||
extern nis_error __nisbind_next __P ((dir_binding *));
|
||||
extern void __nisbind_destroy __P ((dir_binding *));
|
||||
extern nis_error __nisfind_server __P ((const_nis_name, directory_obj **));
|
||||
|
||||
#endif
|
||||
|
||||
__END_DECLS
|
||||
|
||||
#endif /* __RPCSVC_NISLIB_H__ */
|
||||
|
|
|
@ -427,8 +427,9 @@ gr_send_answer (int conn, struct group *grp)
|
|||
struct iovec *vec;
|
||||
size_t *len;
|
||||
gr_response_header resp;
|
||||
size_t total_len;
|
||||
size_t total_len, sum;
|
||||
int nblocks;
|
||||
size_t maxiov;
|
||||
|
||||
resp.version = NSCD_VERSION;
|
||||
if (grp != NULL)
|
||||
|
@ -501,16 +502,21 @@ gr_send_answer (int conn, struct group *grp)
|
|||
}
|
||||
}
|
||||
|
||||
#ifdef UIO_MAXIOV
|
||||
maxiov = UIO_MAXIOV;
|
||||
#else
|
||||
maxiov = sysconf (_SC_UIO_MAXIOV);
|
||||
#endif
|
||||
|
||||
/* Send all the data. */
|
||||
while (nblocks > UIO_MAXIOV)
|
||||
sum = 0;
|
||||
while (nblocks > maxiov)
|
||||
{
|
||||
if (writev (sock[conn], vec, UIO_MAXIOV) != total_len)
|
||||
dbg_log (_("write incomplete on send group answer: %s"),
|
||||
strerror (errno));
|
||||
vec += UIO_MAXIOV;
|
||||
nblocks -= UIO_MAXIOV;
|
||||
sum += writev (sock[conn], vec, maxiov);
|
||||
vec += maxiov;
|
||||
nblocks -= maxiov;
|
||||
}
|
||||
if (writev (sock[conn], vec, nblocks) != total_len)
|
||||
if (sum + writev (sock[conn], vec, nblocks) != total_len)
|
||||
dbg_log (_("write incomplete on send group answer: %s"),
|
||||
strerror (errno));
|
||||
}
|
||||
|
|
|
@ -99,6 +99,8 @@ __nscd_getgr_r (const char *key, request_type type, struct group *resultbuf,
|
|||
request_header req;
|
||||
gr_response_header gr_resp;
|
||||
ssize_t nbytes;
|
||||
size_t maxiov;
|
||||
size_t sum;
|
||||
|
||||
if (sock == -1)
|
||||
{
|
||||
|
@ -232,18 +234,21 @@ __nscd_getgr_r (const char *key, request_type type, struct group *resultbuf,
|
|||
*p++ = '\0';
|
||||
}
|
||||
|
||||
while (i > UIO_MAXIOV)
|
||||
#ifdef UIO_MAXIOV
|
||||
maxiov = UIO_MAXIOV;
|
||||
#else
|
||||
maxiov = sysconf (_SC_UIO_MAXIOV);
|
||||
#endif
|
||||
|
||||
sum = 0;
|
||||
while (i > maxiov)
|
||||
{
|
||||
if (__readv (sock, vec, UIO_MAXIOV) != total_len)
|
||||
{
|
||||
__close (sock);
|
||||
return -1;
|
||||
}
|
||||
vec += UIO_MAXIOV;
|
||||
i -= UIO_MAXIOV;
|
||||
sum += __readv (sock, vec, maxiov);
|
||||
vec += maxiov;
|
||||
i -= maxiov;
|
||||
}
|
||||
|
||||
if (__readv (sock, vec, i) != total_len)
|
||||
if (sum + __readv (sock, vec, i) != total_len)
|
||||
{
|
||||
__close (sock);
|
||||
return -1;
|
||||
|
|
|
@ -267,6 +267,15 @@ cat <<"EOF" | cmp - $testout || result=1
|
|||
`file1'
|
||||
EOF
|
||||
|
||||
# Test NOCHECK with non-existing file in subdir.
|
||||
${elf_objpfx}${rtld_installed_name} --library-path ${library_path} \
|
||||
${common_objpfx}posix/globtest -c "$testdir" "*/blahblah" |
|
||||
sort > $testout
|
||||
cat <<"EOF" | cmp - $testout || result=1
|
||||
`dir1/blahblah'
|
||||
`dir2/blahblah'
|
||||
EOF
|
||||
|
||||
if test $result -eq 0; then
|
||||
rm -fr $testdir $testout
|
||||
fi
|
||||
|
|
|
@ -19,8 +19,9 @@
|
|||
|
||||
#include <ctype.h>
|
||||
#include <printf.h>
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
|
||||
#define NDEBUG 1
|
||||
#include <assert.h>
|
||||
|
@ -271,7 +272,8 @@ parse_one_spec (const UCHAR_T *format, size_t posn, struct printf_spec *spec,
|
|||
spec->info.is_char = 0;
|
||||
|
||||
if (*format == L_('h') || *format == L_('l') || *format == L_('L') ||
|
||||
*format == L_('Z') || *format == L_('q'))
|
||||
*format == L_('Z') || *format == L_('q') || *format == L_('z') ||
|
||||
*format == L_('t') || *format == L_('j'))
|
||||
switch (*format++)
|
||||
{
|
||||
case L_('h'):
|
||||
|
@ -297,11 +299,24 @@ parse_one_spec (const UCHAR_T *format, size_t posn, struct printf_spec *spec,
|
|||
/* 4.4 uses this for long long. */
|
||||
spec->info.is_long_double = 1;
|
||||
break;
|
||||
case L_('z'):
|
||||
case L_('Z'):
|
||||
/* int's are size_t's. */
|
||||
assert (sizeof(size_t) <= sizeof(unsigned long long int));
|
||||
spec->info.is_longlong = sizeof(size_t) > sizeof(unsigned long int);
|
||||
spec->info.is_long = sizeof(size_t) > sizeof(unsigned int);
|
||||
assert (sizeof (size_t) <= sizeof (unsigned long long int));
|
||||
spec->info.is_longlong = sizeof (size_t) > sizeof (unsigned long int);
|
||||
spec->info.is_long = sizeof (size_t) > sizeof (unsigned int);
|
||||
break;
|
||||
case L_('t'):
|
||||
assert (sizeof (ptrdiff_t) <= sizeof (unsigned long long int));
|
||||
spec->info.is_longlong = (sizeof (ptrdiff_t)
|
||||
> sizeof (unsigned long int));
|
||||
spec->info.is_long = sizeof (ptrdiff_t) > sizeof (unsigned int);
|
||||
break;
|
||||
case L_('j'):
|
||||
assert (sizeof (intmax_t) <= sizeof (unsigned long long int));
|
||||
spec->info.is_longlong = (sizeof (intmax_t)
|
||||
> sizeof (unsigned long int));
|
||||
spec->info.is_long = sizeof (intmax_t) > sizeof (unsigned int);
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
#include <limits.h>
|
||||
#include <printf.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
#include <wchar.h>
|
||||
|
@ -250,14 +251,14 @@ vfprintf (FILE *s, const CHAR_T *format, va_list ap)
|
|||
0, 0, 0, 0,
|
||||
0, /* 'a' */ 26, 0, /* 'c' */ 20,
|
||||
/* 'd' */ 15, /* 'e' */ 19, /* 'f' */ 19, /* 'g' */ 19,
|
||||
/* 'h' */ 10, /* 'i' */ 15, 0, 0,
|
||||
/* 'h' */ 10, /* 'i' */ 15, /* 'j' */ 28, 0,
|
||||
/* 'l' */ 11, /* 'm' */ 24, /* 'n' */ 23, /* 'o' */ 17,
|
||||
/* 'p' */ 22, /* 'q' */ 12, 0, /* 's' */ 21,
|
||||
0, /* 'u' */ 16, 0, 0,
|
||||
/* 'x' */ 18
|
||||
/* 't' */ 27, /* 'u' */ 16, 0, 0,
|
||||
/* 'x' */ 18, 0, /* 'z' */ 13
|
||||
};
|
||||
|
||||
#define NOT_IN_JUMP_RANGE(Ch) ((Ch) < ' ' || (Ch) > 'x')
|
||||
#define NOT_IN_JUMP_RANGE(Ch) ((Ch) < ' ' || (Ch) > 'z')
|
||||
#define CHAR_CLASS(Ch) (jump_table[(int) (Ch) - ' '])
|
||||
#define JUMP(ChExpr, table) \
|
||||
do \
|
||||
|
@ -272,7 +273,7 @@ vfprintf (FILE *s, const CHAR_T *format, va_list ap)
|
|||
|
||||
#define STEP0_3_TABLE \
|
||||
/* Step 0: at the beginning. */ \
|
||||
static const void *step0_jumps[27] = \
|
||||
static const void *step0_jumps[29] = \
|
||||
{ \
|
||||
REF (form_unknown), \
|
||||
REF (flag_space), /* for ' ' */ \
|
||||
|
@ -287,7 +288,7 @@ vfprintf (FILE *s, const CHAR_T *format, va_list ap)
|
|||
REF (mod_half), /* for 'h' */ \
|
||||
REF (mod_long), /* for 'l' */ \
|
||||
REF (mod_longlong), /* for 'L', 'q' */ \
|
||||
REF (mod_size_t), /* for 'Z' */ \
|
||||
REF (mod_size_t), /* for 'z', 'Z' */ \
|
||||
REF (form_percent), /* for '%' */ \
|
||||
REF (form_integer), /* for 'd', 'i' */ \
|
||||
REF (form_unsigned), /* for 'u' */ \
|
||||
|
@ -300,10 +301,12 @@ vfprintf (FILE *s, const CHAR_T *format, va_list ap)
|
|||
REF (form_number), /* for 'n' */ \
|
||||
REF (form_strerror), /* for 'm' */ \
|
||||
REF (form_wcharacter), /* for 'C' */ \
|
||||
REF (form_floathex) /* for 'A', 'a' */ \
|
||||
REF (form_floathex), /* for 'A', 'a' */ \
|
||||
REF (mod_ptrdiff_t), /* for 't' */ \
|
||||
REF (mod_intmax_t), /* for 'j' */ \
|
||||
}; \
|
||||
/* Step 1: after processing width. */ \
|
||||
static const void *step1_jumps[27] = \
|
||||
static const void *step1_jumps[29] = \
|
||||
{ \
|
||||
REF (form_unknown), \
|
||||
REF (form_unknown), /* for ' ' */ \
|
||||
|
@ -318,7 +321,7 @@ vfprintf (FILE *s, const CHAR_T *format, va_list ap)
|
|||
REF (mod_half), /* for 'h' */ \
|
||||
REF (mod_long), /* for 'l' */ \
|
||||
REF (mod_longlong), /* for 'L', 'q' */ \
|
||||
REF (mod_size_t), /* for 'Z' */ \
|
||||
REF (mod_size_t), /* for 'z', 'Z' */ \
|
||||
REF (form_percent), /* for '%' */ \
|
||||
REF (form_integer), /* for 'd', 'i' */ \
|
||||
REF (form_unsigned), /* for 'u' */ \
|
||||
|
@ -331,10 +334,12 @@ vfprintf (FILE *s, const CHAR_T *format, va_list ap)
|
|||
REF (form_number), /* for 'n' */ \
|
||||
REF (form_strerror), /* for 'm' */ \
|
||||
REF (form_wcharacter), /* for 'C' */ \
|
||||
REF (form_floathex) /* for 'A', 'a' */ \
|
||||
REF (form_floathex), /* for 'A', 'a' */ \
|
||||
REF (mod_ptrdiff_t), /* for 't' */ \
|
||||
REF (mod_intmax_t) /* for 'j' */ \
|
||||
}; \
|
||||
/* Step 2: after processing precision. */ \
|
||||
static const void *step2_jumps[27] = \
|
||||
static const void *step2_jumps[29] = \
|
||||
{ \
|
||||
REF (form_unknown), \
|
||||
REF (form_unknown), /* for ' ' */ \
|
||||
|
@ -349,7 +354,7 @@ vfprintf (FILE *s, const CHAR_T *format, va_list ap)
|
|||
REF (mod_half), /* for 'h' */ \
|
||||
REF (mod_long), /* for 'l' */ \
|
||||
REF (mod_longlong), /* for 'L', 'q' */ \
|
||||
REF (mod_size_t), /* for 'Z' */ \
|
||||
REF (mod_size_t), /* for 'z', 'Z' */ \
|
||||
REF (form_percent), /* for '%' */ \
|
||||
REF (form_integer), /* for 'd', 'i' */ \
|
||||
REF (form_unsigned), /* for 'u' */ \
|
||||
|
@ -362,10 +367,12 @@ vfprintf (FILE *s, const CHAR_T *format, va_list ap)
|
|||
REF (form_number), /* for 'n' */ \
|
||||
REF (form_strerror), /* for 'm' */ \
|
||||
REF (form_wcharacter), /* for 'C' */ \
|
||||
REF (form_floathex) /* for 'A', 'a' */ \
|
||||
REF (form_floathex), /* for 'A', 'a' */ \
|
||||
REF (mod_ptrdiff_t), /* for 't' */ \
|
||||
REF (mod_intmax_t) /* for 'j' */ \
|
||||
}; \
|
||||
/* Step 3a: after processing first 'h' modifier. */ \
|
||||
static const void *step3a_jumps[27] = \
|
||||
static const void *step3a_jumps[29] = \
|
||||
{ \
|
||||
REF (form_unknown), \
|
||||
REF (form_unknown), /* for ' ' */ \
|
||||
|
@ -380,7 +387,7 @@ vfprintf (FILE *s, const CHAR_T *format, va_list ap)
|
|||
REF (mod_halfhalf), /* for 'h' */ \
|
||||
REF (form_unknown), /* for 'l' */ \
|
||||
REF (form_unknown), /* for 'L', 'q' */ \
|
||||
REF (form_unknown), /* for 'Z' */ \
|
||||
REF (form_unknown), /* for 'z', 'Z' */ \
|
||||
REF (form_percent), /* for '%' */ \
|
||||
REF (form_integer), /* for 'd', 'i' */ \
|
||||
REF (form_unsigned), /* for 'u' */ \
|
||||
|
@ -393,10 +400,12 @@ vfprintf (FILE *s, const CHAR_T *format, va_list ap)
|
|||
REF (form_number), /* for 'n' */ \
|
||||
REF (form_unknown), /* for 'm' */ \
|
||||
REF (form_unknown), /* for 'C' */ \
|
||||
REF (form_unknown) /* for 'A', 'a' */ \
|
||||
REF (form_unknown), /* for 'A', 'a' */ \
|
||||
REF (form_unknown), /* for 't' */ \
|
||||
REF (form_unknown) /* for 'j' */ \
|
||||
}; \
|
||||
/* Step 3b: after processing first 'l' modifier. */ \
|
||||
static const void *step3b_jumps[27] = \
|
||||
static const void *step3b_jumps[29] = \
|
||||
{ \
|
||||
REF (form_unknown), \
|
||||
REF (form_unknown), /* for ' ' */ \
|
||||
|
@ -411,7 +420,7 @@ vfprintf (FILE *s, const CHAR_T *format, va_list ap)
|
|||
REF (form_unknown), /* for 'h' */ \
|
||||
REF (mod_longlong), /* for 'l' */ \
|
||||
REF (form_unknown), /* for 'L', 'q' */ \
|
||||
REF (form_unknown), /* for 'Z' */ \
|
||||
REF (form_unknown), /* for 'z', 'Z' */ \
|
||||
REF (form_percent), /* for '%' */ \
|
||||
REF (form_integer), /* for 'd', 'i' */ \
|
||||
REF (form_unsigned), /* for 'u' */ \
|
||||
|
@ -424,12 +433,14 @@ vfprintf (FILE *s, const CHAR_T *format, va_list ap)
|
|||
REF (form_number), /* for 'n' */ \
|
||||
REF (form_strerror), /* for 'm' */ \
|
||||
REF (form_wcharacter), /* for 'C' */ \
|
||||
REF (form_floathex) /* for 'A', 'a' */ \
|
||||
REF (form_floathex), /* for 'A', 'a' */ \
|
||||
REF (form_unknown), /* for 't' */ \
|
||||
REF (form_unknown) /* for 'j' */ \
|
||||
}
|
||||
|
||||
#define STEP4_TABLE \
|
||||
/* Step 4: processing format specifier. */ \
|
||||
static const void *step4_jumps[27] = \
|
||||
static const void *step4_jumps[29] = \
|
||||
{ \
|
||||
REF (form_unknown), \
|
||||
REF (form_unknown), /* for ' ' */ \
|
||||
|
@ -444,7 +455,7 @@ vfprintf (FILE *s, const CHAR_T *format, va_list ap)
|
|||
REF (form_unknown), /* for 'h' */ \
|
||||
REF (form_unknown), /* for 'l' */ \
|
||||
REF (form_unknown), /* for 'L', 'q' */ \
|
||||
REF (form_unknown), /* for 'Z' */ \
|
||||
REF (form_unknown), /* for 'z', 'Z' */ \
|
||||
REF (form_percent), /* for '%' */ \
|
||||
REF (form_integer), /* for 'd', 'i' */ \
|
||||
REF (form_unsigned), /* for 'u' */ \
|
||||
|
@ -457,7 +468,9 @@ vfprintf (FILE *s, const CHAR_T *format, va_list ap)
|
|||
REF (form_number), /* for 'n' */ \
|
||||
REF (form_strerror), /* for 'm' */ \
|
||||
REF (form_wcharacter), /* for 'C' */ \
|
||||
REF (form_floathex) /* for 'A', 'a' */ \
|
||||
REF (form_floathex), /* for 'A', 'a' */ \
|
||||
REF (form_unknown), /* for 't' */ \
|
||||
REF (form_unknown) /* for 'j' */ \
|
||||
}
|
||||
|
||||
|
||||
|
@ -1178,6 +1191,16 @@ vfprintf (FILE *s, const CHAR_T *format, va_list ap)
|
|||
is_long = sizeof (size_t) > sizeof (unsigned int);
|
||||
JUMP (*++f, step4_jumps);
|
||||
|
||||
LABEL (mod_ptrdiff_t):
|
||||
is_longlong = sizeof (ptrdiff_t) > sizeof (unsigned long int);
|
||||
is_long = sizeof (ptrdiff_t) > sizeof (unsigned int);
|
||||
JUMP (*++f, step4_jumps);
|
||||
|
||||
LABEL (mod_intmax_t):
|
||||
is_longlong = sizeof (intmax_t) > sizeof (unsigned long int);
|
||||
is_long = sizeof (intmax_t) > sizeof (unsigned int);
|
||||
JUMP (*++f, step4_jumps);
|
||||
|
||||
/* Process current format. */
|
||||
while (1)
|
||||
{
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
#include <ctype.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <wctype.h>
|
||||
|
@ -407,7 +408,8 @@ __vfscanf (FILE *s, const char *format, va_list argptr)
|
|||
width = -1;
|
||||
|
||||
/* Check for type modifiers. */
|
||||
while (*f == 'h' || *f == 'l' || *f == 'L' || *f == 'a' || *f == 'q')
|
||||
while (*f == 'h' || *f == 'l' || *f == 'L' || *f == 'a' || *f == 'q'
|
||||
|| *f == 'z' || *f == 't' || *f == 'j')
|
||||
switch (*f++)
|
||||
{
|
||||
case 'h':
|
||||
|
@ -459,6 +461,30 @@ __vfscanf (FILE *s, const char *format, va_list argptr)
|
|||
arg and fill it in with a malloc'd pointer. */
|
||||
flags |= MALLOC;
|
||||
break;
|
||||
case 'z':
|
||||
if (flags & (SHORT|LONGDBL|CHAR))
|
||||
conv_error ();
|
||||
if (sizeof (size_t) > sizeof (unsigned long int))
|
||||
flags |= LONGDBL;
|
||||
else if (sizeof (size_t) > sizeof (unsigned int))
|
||||
flags |= LONG;
|
||||
break;
|
||||
case 'j':
|
||||
if (flags & (SHORT|LONGDBL|CHAR))
|
||||
conv_error ();
|
||||
if (sizeof (intmax_t) > sizeof (unsigned long int))
|
||||
flags |= LONGDBL;
|
||||
else if (sizeof (intmax_t) > sizeof (unsigned int))
|
||||
flags |= LONG;
|
||||
break;
|
||||
case 't':
|
||||
if (flags & (SHORT|LONGDBL|CHAR))
|
||||
conv_error ();
|
||||
if (sizeof (ptrdiff_t) > sizeof (unsigned long int))
|
||||
flags |= LONGDBL;
|
||||
else if (sizeof (ptrdiff_t) > sizeof (unsigned int))
|
||||
flags |= LONG;
|
||||
break;
|
||||
}
|
||||
|
||||
/* End of the format string? */
|
||||
|
|
|
@ -147,7 +147,7 @@ extern int errno;
|
|||
# define LONG_MAX ((long int) (ULONG_MAX >> 1))
|
||||
# endif
|
||||
# define STRTOL_LONG_MIN LONG_MIN
|
||||
# define STRTOL_LONG_MAX ULONG_MAX
|
||||
# define STRTOL_LONG_MAX LONG_MAX
|
||||
# define STRTOL_ULONG_MAX ULONG_MAX
|
||||
#endif
|
||||
|
||||
|
|
|
@ -66,7 +66,8 @@ routines := auth_none auth_unix authuxprot bindrsvprt \
|
|||
svc_tcp svc_udp xdr xdr_array xdr_float xdr_mem \
|
||||
xdr_rec xdr_ref xdr_stdio publickey xdr_sizeof \
|
||||
auth_des authdes_prot des_crypt des_impl des_soft \
|
||||
key_call key_prot netname openchild rtime svcauth_des xcrypt
|
||||
key_call key_prot netname openchild rtime svcauth_des xcrypt\
|
||||
clnt_unix svc_unix
|
||||
|
||||
others := rpcinfo
|
||||
install-bin := rpcgen
|
||||
|
|
|
@ -59,7 +59,7 @@ libc {
|
|||
authdes_create; authdes_getucred; authdes_pk_create;
|
||||
|
||||
# c*
|
||||
cbc_crypt;
|
||||
cbc_crypt; clntunix_create;
|
||||
|
||||
# d*
|
||||
des_setparity;
|
||||
|
@ -87,6 +87,9 @@ libc {
|
|||
# r*
|
||||
rtime;
|
||||
|
||||
# s*
|
||||
svcunix_create; svcunixfd_create;
|
||||
|
||||
# u*
|
||||
user2netname;
|
||||
|
||||
|
|
|
@ -57,11 +57,27 @@ clnt_create (const char *hostname, u_long prog, u_long vers,
|
|||
size_t prtbuflen;
|
||||
char *prttmpbuf;
|
||||
struct sockaddr_in sin;
|
||||
struct sockaddr_un sun;
|
||||
int sock;
|
||||
struct timeval tv;
|
||||
CLIENT *client;
|
||||
int herr;
|
||||
|
||||
if (strcmp (proto, "unix") == 0)
|
||||
{
|
||||
__bzero ((char *)&sun, sizeof (sun));
|
||||
sun.sun_family = AF_UNIX;
|
||||
strcpy (sun.sun_path, hostname);
|
||||
sock = RPC_ANYSOCK;
|
||||
client = clntunix_create (&sun, prog, vers, &sock, 0, 0);
|
||||
if (client == NULL)
|
||||
return NULL;
|
||||
tv.tv_sec = 25;
|
||||
tv.tv_usec = 0;
|
||||
clnt_control (client, CLSET_TIMEOUT, (char *)&tv);
|
||||
return client;
|
||||
}
|
||||
|
||||
hstbuflen = 1024;
|
||||
hsttmpbuf = __alloca (hstbuflen);
|
||||
while (__gethostbyname_r (hostname, &hostbuf, hsttmpbuf, hstbuflen,
|
||||
|
|
|
@ -0,0 +1,573 @@
|
|||
/*
|
||||
* 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_unix.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 <netdb.h>
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <rpc/rpc.h>
|
||||
#include <sys/uio.h>
|
||||
#include <sys/poll.h>
|
||||
#include <sys/socket.h>
|
||||
#include <rpc/pmap_clnt.h>
|
||||
|
||||
#define MCALL_MSG_SIZE 24
|
||||
|
||||
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_un 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;
|
||||
};
|
||||
|
||||
static int readunix (char *, char *, int);
|
||||
static int writeunix (char *, char *, int);
|
||||
|
||||
static enum clnt_stat clntunix_call (CLIENT *, u_long, xdrproc_t, caddr_t,
|
||||
xdrproc_t, caddr_t, struct timeval);
|
||||
static void clntunix_abort (void);
|
||||
static void clntunix_geterr (CLIENT *, struct rpc_err *);
|
||||
static bool_t clntunix_freeres (CLIENT *, xdrproc_t, caddr_t);
|
||||
static bool_t clntunix_control (CLIENT *, int, char *);
|
||||
static void clntunix_destroy (CLIENT *);
|
||||
|
||||
static struct clnt_ops unix_ops =
|
||||
{
|
||||
clntunix_call,
|
||||
clntunix_abort,
|
||||
clntunix_geterr,
|
||||
clntunix_freeres,
|
||||
clntunix_destroy,
|
||||
clntunix_control
|
||||
};
|
||||
|
||||
/*
|
||||
* 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 *
|
||||
clntunix_create (struct sockaddr_un *raddr, u_long prog, u_long vers,
|
||||
int *sockp, u_int sendsz, u_int recvsz)
|
||||
{
|
||||
CLIENT *h;
|
||||
struct ct_data *ct = (struct ct_data *) mem_alloc (sizeof (*ct));
|
||||
struct timeval now;
|
||||
struct rpc_msg call_msg;
|
||||
int len;
|
||||
|
||||
h = (CLIENT *) mem_alloc (sizeof (*h));
|
||||
if (h == NULL)
|
||||
{
|
||||
(void) fputs (_("clntunix_create: out of memory\n"), stderr);
|
||||
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) fputs (_("clntunix_create: out of memory\n"), stderr);
|
||||
rpc_createerr.cf_stat = RPC_SYSTEMERROR;
|
||||
rpc_createerr.cf_error.re_errno = errno;
|
||||
goto fooy;
|
||||
}
|
||||
|
||||
/*
|
||||
* If no socket given, open one
|
||||
*/
|
||||
if (*sockp < 0)
|
||||
{
|
||||
*sockp = __socket (AF_UNIX, SOCK_STREAM, 0);
|
||||
len = strlen (raddr->sun_path) + sizeof (raddr->sun_family) + 1;
|
||||
if (*sockp < 0
|
||||
|| __connect (*sockp, (struct sockaddr *) raddr, len) < 0)
|
||||
{
|
||||
rpc_createerr.cf_stat = RPC_SYSTEMERROR;
|
||||
rpc_createerr.cf_error.re_errno = errno;
|
||||
if (*sockp != -1)
|
||||
__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
|
||||
*/
|
||||
__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 static 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)
|
||||
__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, readunix, writeunix);
|
||||
h->cl_ops = &unix_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
|
||||
clntunix_call (h, proc, xdr_args, args_ptr, xdr_results, results_ptr, timeout)
|
||||
CLIENT *h;
|
||||
u_long proc;
|
||||
xdrproc_t xdr_args;
|
||||
caddr_t args_ptr;
|
||||
xdrproc_t xdr_results;
|
||||
caddr_t results_ptr;
|
||||
struct timeval timeout;
|
||||
{
|
||||
struct ct_data *ct = (struct ct_data *) h->cl_private;
|
||||
XDR *xdrs = &(ct->ct_xdrs);
|
||||
struct rpc_msg reply_msg;
|
||||
u_long x_id;
|
||||
u_int32_t *msg_x_id = (u_int32_t *) (ct->ct_mcall); /* yuk */
|
||||
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 = (xdrproc_t)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
|
||||
clntunix_geterr (CLIENT *h, struct rpc_err *errp)
|
||||
{
|
||||
struct ct_data *ct = (struct ct_data *) h->cl_private;
|
||||
|
||||
*errp = ct->ct_error;
|
||||
}
|
||||
|
||||
static bool_t
|
||||
clntunix_freeres (cl, xdr_res, res_ptr)
|
||||
CLIENT *cl;
|
||||
xdrproc_t xdr_res;
|
||||
caddr_t res_ptr;
|
||||
{
|
||||
struct ct_data *ct = (struct ct_data *) cl->cl_private;
|
||||
XDR *xdrs = &(ct->ct_xdrs);
|
||||
|
||||
xdrs->x_op = XDR_FREE;
|
||||
return (*xdr_res) (xdrs, res_ptr);
|
||||
}
|
||||
|
||||
static void
|
||||
clntunix_abort ()
|
||||
{
|
||||
}
|
||||
|
||||
static bool_t
|
||||
clntunix_control (CLIENT *cl, int request, char *info)
|
||||
{
|
||||
struct ct_data *ct = (struct ct_data *) cl->cl_private;
|
||||
|
||||
|
||||
switch (request)
|
||||
{
|
||||
case CLSET_FD_CLOSE:
|
||||
ct->ct_closeit = TRUE;
|
||||
break;
|
||||
case CLSET_FD_NCLOSE:
|
||||
ct->ct_closeit = FALSE;
|
||||
break;
|
||||
case CLSET_TIMEOUT:
|
||||
ct->ct_wait = *(struct timeval *) info;
|
||||
break;
|
||||
case CLGET_TIMEOUT:
|
||||
*(struct timeval *) info = ct->ct_wait;
|
||||
break;
|
||||
case CLGET_SERVER_ADDR:
|
||||
*(struct sockaddr_un *) info = ct->ct_addr;
|
||||
break;
|
||||
case CLGET_FD:
|
||||
*(int *)info = ct->ct_sock;
|
||||
break;
|
||||
case CLGET_XID:
|
||||
/*
|
||||
* use the knowledge that xid is the
|
||||
* first element in the call structure *.
|
||||
* This will get the xid of the PREVIOUS call
|
||||
*/
|
||||
*(u_long *) info = ntohl (*(u_long *)ct->ct_mcall);
|
||||
break;
|
||||
case CLSET_XID:
|
||||
/* This will set the xid of the NEXT call */
|
||||
*(u_long *) ct->ct_mcall = htonl (*(u_long *)info - 1);
|
||||
/* decrement by 1 as clntunix_call() increments once */
|
||||
case CLGET_VERS:
|
||||
/*
|
||||
* This RELIES on the information that, in the call body,
|
||||
* the version number field is the fifth field from the
|
||||
* begining of the RPC header. MUST be changed if the
|
||||
* call_struct is changed
|
||||
*/
|
||||
*(u_long *) info = ntohl (*(u_long *) (ct->ct_mcall
|
||||
+ 4 * BYTES_PER_XDR_UNIT));
|
||||
break;
|
||||
case CLSET_VERS:
|
||||
*(u_long *) (ct->ct_mcall + 4 * BYTES_PER_XDR_UNIT)
|
||||
= htonl (*(u_long *) info);
|
||||
break;
|
||||
case CLGET_PROG:
|
||||
/*
|
||||
* This RELIES on the information that, in the call body,
|
||||
* the program number field is the field from the
|
||||
* begining of the RPC header. MUST be changed if the
|
||||
* call_struct is changed
|
||||
*/
|
||||
*(u_long *) info = ntohl (*(u_long *) (ct->ct_mcall
|
||||
+ 3 * BYTES_PER_XDR_UNIT));
|
||||
break;
|
||||
case CLSET_PROG:
|
||||
*(u_long *) (ct->ct_mcall + 3 * BYTES_PER_XDR_UNIT)
|
||||
= htonl(*(u_long *) info);
|
||||
break;
|
||||
/* The following are only possible with TI-RPC */
|
||||
case CLGET_RETRY_TIMEOUT:
|
||||
case CLSET_RETRY_TIMEOUT:
|
||||
case CLGET_SVC_ADDR:
|
||||
case CLSET_SVC_ADDR:
|
||||
case CLSET_PUSH_TIMOD:
|
||||
case CLSET_POP_TIMOD:
|
||||
default:
|
||||
return FALSE;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
clntunix_destroy (CLIENT *h)
|
||||
{
|
||||
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));
|
||||
}
|
||||
|
||||
struct cmessage {
|
||||
struct cmsghdr cmsg;
|
||||
struct cmsgcred cmcred;
|
||||
};
|
||||
|
||||
static int
|
||||
__msgread (int sock, void *buf, size_t cnt)
|
||||
{
|
||||
struct iovec iov[1];
|
||||
struct msghdr msg;
|
||||
struct cmessage cm;
|
||||
int on = 1;
|
||||
|
||||
iov[0].iov_base = buf;
|
||||
iov[0].iov_len = cnt;
|
||||
|
||||
msg.msg_iov = iov;
|
||||
msg.msg_iovlen = 1;
|
||||
msg.msg_name = NULL;
|
||||
msg.msg_namelen = 0;
|
||||
msg.msg_control = (caddr_t)&cm;
|
||||
msg.msg_controllen = sizeof(struct cmessage);
|
||||
msg.msg_flags = 0;
|
||||
|
||||
setsockopt (sock, SOL_SOCKET, SO_PASSCRED, &on, sizeof (on));
|
||||
|
||||
return recvmsg (sock, &msg, 0);
|
||||
}
|
||||
|
||||
static int
|
||||
__msgwrite (int sock, void *buf, size_t cnt)
|
||||
{
|
||||
#ifndef SCM_CRED
|
||||
/* We cannot implement this reliably. */
|
||||
__set_errno (ENOSYS);
|
||||
#else
|
||||
struct iovec iov[1];
|
||||
struct msghdr msg;
|
||||
struct cmessage cm;
|
||||
int len;
|
||||
|
||||
iov[0].iov_base = buf;
|
||||
iov[0].iov_len = cnt;
|
||||
|
||||
cm.cmsg.cmsg_type = SCM_CREDS;
|
||||
cm.cmsg.cmsg_level = SOL_SOCKET;
|
||||
cm.cmsg.cmsg_len = sizeof (struct cmessage);
|
||||
/* XXX I'm not sure, if gete?id() is always correct, or if we should use
|
||||
get?id(). But since keyserv needs geteuid(), we have no other chance.
|
||||
It would be much better, if the kernel could pass both to the server. */
|
||||
cm.cmcred.cmcred_pid = __getpid ();
|
||||
cm.cmcred.cmcred_uid = __geteuid ();
|
||||
cm.cmcred.cmcred_gid = __getegid ();
|
||||
|
||||
msg.msg_iov = iov;
|
||||
msg.msg_iovlen = 1;
|
||||
msg.msg_name = NULL;
|
||||
msg.msg_namelen = 0;
|
||||
msg.msg_control = (caddr_t) &cm;
|
||||
msg.msg_controllen = sizeof (struct cmessage);
|
||||
msg.msg_flags = 0;
|
||||
|
||||
return sendmsg (sock, &msg, 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Interface between xdr serializer and unix connection.
|
||||
* Behaves like the system calls, read & write, but keeps some error state
|
||||
* around for the rpc level.
|
||||
*/
|
||||
static int
|
||||
readunix (char *ctptr, char *buf, int len)
|
||||
{
|
||||
struct ct_data *ct = (struct ct_data *) ctptr;
|
||||
struct pollfd fd;
|
||||
int milliseconds = ((ct->ct_wait.tv_sec * 1000)
|
||||
+ (ct->ct_wait.tv_usec / 1000));
|
||||
|
||||
if (len == 0)
|
||||
return 0;
|
||||
|
||||
fd.fd = ct->ct_sock;
|
||||
fd.events = POLLIN;
|
||||
while (TRUE)
|
||||
{
|
||||
switch (__poll (&fd, 1, milliseconds))
|
||||
{
|
||||
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 = __msgread (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
|
||||
writeunix (char *ctptr, char *buf, int len)
|
||||
{
|
||||
int i, cnt;
|
||||
struct ct_data *ct = (struct ct_data *) ctptr;
|
||||
|
||||
for (cnt = len; cnt > 0; cnt -= i, buf += i)
|
||||
{
|
||||
if ((i = __msgwrite (ct->ct_sock, buf, cnt)) == -1)
|
||||
{
|
||||
ct->ct_error.re_errno = errno;
|
||||
ct->ct_error.re_status = RPC_CANTSEND;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
return len;
|
||||
}
|
|
@ -38,6 +38,7 @@
|
|||
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <signal.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
|
@ -47,6 +48,7 @@
|
|||
#include <sys/param.h>
|
||||
#include <sys/socket.h>
|
||||
#include <rpc/key_prot.h>
|
||||
#include <bits/libc-lock.h>
|
||||
|
||||
#define KEY_TIMEOUT 5 /* per-try timeout in seconds */
|
||||
#define KEY_NRETRY 12 /* number of retries */
|
||||
|
@ -268,8 +270,8 @@ des_block *(*__key_gendes_LOCAL) (uid_t, char *) = 0;
|
|||
|
||||
static int
|
||||
internal_function
|
||||
key_call (u_long proc, xdrproc_t xdr_arg, char *arg,
|
||||
xdrproc_t xdr_rslt, char *rslt)
|
||||
key_call_keyenvoy (u_long proc, xdrproc_t xdr_arg, char *arg,
|
||||
xdrproc_t xdr_rslt, char *rslt)
|
||||
{
|
||||
XDR xdrargs;
|
||||
XDR xdrrslt;
|
||||
|
@ -283,28 +285,6 @@ key_call (u_long proc, xdrproc_t xdr_arg, char *arg,
|
|||
uid_t euid;
|
||||
static char MESSENGER[] = "/usr/etc/keyenvoy";
|
||||
|
||||
if (proc == KEY_ENCRYPT_PK && __key_encryptsession_pk_LOCAL)
|
||||
{
|
||||
cryptkeyres *res;
|
||||
res = (*__key_encryptsession_pk_LOCAL) (__geteuid (), arg);
|
||||
*(cryptkeyres *) rslt = *res;
|
||||
return 1;
|
||||
}
|
||||
else if (proc == KEY_DECRYPT_PK && __key_decryptsession_pk_LOCAL)
|
||||
{
|
||||
cryptkeyres *res;
|
||||
res = (*__key_decryptsession_pk_LOCAL) (__geteuid (), arg);
|
||||
*(cryptkeyres *) rslt = *res;
|
||||
return 1;
|
||||
}
|
||||
else if (proc == KEY_GEN && __key_gendes_LOCAL)
|
||||
{
|
||||
des_block *res;
|
||||
res = (*__key_gendes_LOCAL) (__geteuid (), 0);
|
||||
*(des_block *) rslt = *res;
|
||||
return 1;
|
||||
}
|
||||
|
||||
success = 1;
|
||||
sigemptyset (&mask);
|
||||
sigaddset (&mask, SIGCHLD);
|
||||
|
@ -365,3 +345,175 @@ key_call (u_long proc, xdrproc_t xdr_arg, char *arg,
|
|||
|
||||
return success;
|
||||
}
|
||||
|
||||
struct key_call_private {
|
||||
CLIENT *client; /* Client handle */
|
||||
pid_t pid; /* process-id at moment of creation */
|
||||
uid_t uid; /* user-id at last authorization */
|
||||
};
|
||||
static struct key_call_private *key_call_private_main = NULL;
|
||||
__libc_lock_define_initialized (static, keycall_lock)
|
||||
|
||||
/*
|
||||
* Keep the handle cached. This call may be made quite often.
|
||||
*/
|
||||
static CLIENT *
|
||||
getkeyserv_handle (int vers)
|
||||
{
|
||||
struct key_call_private *kcp = key_call_private_main;
|
||||
struct timeval wait_time;
|
||||
int fd;
|
||||
struct sockaddr_un name;
|
||||
int namelen = sizeof(struct sockaddr_un);
|
||||
|
||||
#define TOTAL_TIMEOUT 30 /* total timeout talking to keyserver */
|
||||
#define TOTAL_TRIES 5 /* Number of tries */
|
||||
|
||||
if (kcp == (struct key_call_private *)NULL)
|
||||
{
|
||||
kcp = (struct key_call_private *)malloc (sizeof (*kcp));
|
||||
if (kcp == (struct key_call_private *)NULL)
|
||||
return (CLIENT *) NULL;
|
||||
|
||||
key_call_private_main = kcp;
|
||||
kcp->client = NULL;
|
||||
}
|
||||
|
||||
/* if pid has changed, destroy client and rebuild */
|
||||
if (kcp->client != NULL && kcp->pid != __getpid ())
|
||||
{
|
||||
clnt_destroy (kcp->client);
|
||||
kcp->client = NULL;
|
||||
}
|
||||
|
||||
if (kcp->client != NULL)
|
||||
{
|
||||
/* if other side closed socket, build handle again */
|
||||
clnt_control (kcp->client, CLGET_FD, (char *)&fd);
|
||||
if (getpeername (fd,(struct sockaddr *)&name,&namelen) == -1)
|
||||
{
|
||||
auth_destroy (kcp->client->cl_auth);
|
||||
clnt_destroy (kcp->client);
|
||||
kcp->client = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (kcp->client != NULL)
|
||||
{
|
||||
/* if uid has changed, build client handle again */
|
||||
if (kcp->uid != __geteuid ())
|
||||
{
|
||||
kcp->uid = __geteuid ();
|
||||
auth_destroy (kcp->client->cl_auth);
|
||||
kcp->client->cl_auth =
|
||||
authunix_create ((char *)"", kcp->uid, 0, 0, NULL);
|
||||
if (kcp->client->cl_auth == NULL)
|
||||
{
|
||||
clnt_destroy (kcp->client);
|
||||
kcp->client = NULL;
|
||||
return ((CLIENT *) NULL);
|
||||
}
|
||||
}
|
||||
/* Change the version number to the new one */
|
||||
clnt_control (kcp->client, CLSET_VERS, (void *)&vers);
|
||||
return kcp->client;
|
||||
}
|
||||
|
||||
if ((kcp->client == (CLIENT *) NULL))
|
||||
/* Use the AF_UNIX transport */
|
||||
kcp->client = clnt_create ("/var/run/keyservsock", KEY_PROG, vers, "unix");
|
||||
|
||||
if (kcp->client == (CLIENT *) NULL)
|
||||
return (CLIENT *) NULL;
|
||||
|
||||
kcp->uid = __geteuid ();
|
||||
kcp->pid = __getpid ();
|
||||
kcp->client->cl_auth = authunix_create ((char *)"", kcp->uid, 0, 0, NULL);
|
||||
if (kcp->client->cl_auth == NULL)
|
||||
{
|
||||
clnt_destroy (kcp->client);
|
||||
kcp->client = NULL;
|
||||
return (CLIENT *) NULL;
|
||||
}
|
||||
|
||||
wait_time.tv_sec = TOTAL_TIMEOUT/TOTAL_TRIES;
|
||||
wait_time.tv_usec = 0;
|
||||
clnt_control (kcp->client, CLSET_RETRY_TIMEOUT,
|
||||
(char *)&wait_time);
|
||||
if (clnt_control (kcp->client, CLGET_FD, (char *)&fd))
|
||||
fcntl (fd, F_SETFD, 1); /* make it "close on exec" */
|
||||
|
||||
return kcp->client;
|
||||
}
|
||||
|
||||
/* returns 0 on failure, 1 on success */
|
||||
static int
|
||||
internal_function
|
||||
key_call_socket (u_long proc, xdrproc_t xdr_arg, char *arg,
|
||||
xdrproc_t xdr_rslt, char *rslt)
|
||||
{
|
||||
CLIENT *clnt;
|
||||
struct timeval wait_time;
|
||||
int result = 0;
|
||||
|
||||
__libc_lock_lock (keycall_lock);
|
||||
if ((proc == KEY_ENCRYPT_PK) || (proc == KEY_DECRYPT_PK) ||
|
||||
(proc == KEY_NET_GET) || (proc == KEY_NET_PUT) ||
|
||||
(proc == KEY_GET_CONV))
|
||||
clnt = getkeyserv_handle(2); /* talk to version 2 */
|
||||
else
|
||||
clnt = getkeyserv_handle(1); /* talk to version 1 */
|
||||
|
||||
if (clnt != NULL)
|
||||
{
|
||||
wait_time.tv_sec = TOTAL_TIMEOUT;
|
||||
wait_time.tv_usec = 0;
|
||||
|
||||
if (clnt_call (clnt, proc, xdr_arg, arg, xdr_rslt, rslt,
|
||||
wait_time) == RPC_SUCCESS)
|
||||
result = 1;
|
||||
}
|
||||
|
||||
__libc_lock_unlock (keycall_lock);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/* returns 0 on failure, 1 on success */
|
||||
static int
|
||||
internal_function
|
||||
key_call (u_long proc, xdrproc_t xdr_arg, char *arg,
|
||||
xdrproc_t xdr_rslt, char *rslt)
|
||||
{
|
||||
static int use_keyenvoy = 0;
|
||||
|
||||
if (proc == KEY_ENCRYPT_PK && __key_encryptsession_pk_LOCAL)
|
||||
{
|
||||
cryptkeyres *res;
|
||||
res = (*__key_encryptsession_pk_LOCAL) (__geteuid (), arg);
|
||||
*(cryptkeyres *) rslt = *res;
|
||||
return 1;
|
||||
}
|
||||
else if (proc == KEY_DECRYPT_PK && __key_decryptsession_pk_LOCAL)
|
||||
{
|
||||
cryptkeyres *res;
|
||||
res = (*__key_decryptsession_pk_LOCAL) (__geteuid (), arg);
|
||||
*(cryptkeyres *) rslt = *res;
|
||||
return 1;
|
||||
}
|
||||
else if (proc == KEY_GEN && __key_gendes_LOCAL)
|
||||
{
|
||||
des_block *res;
|
||||
res = (*__key_gendes_LOCAL) (__geteuid (), 0);
|
||||
*(des_block *) rslt = *res;
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!use_keyenvoy)
|
||||
{
|
||||
if (key_call_socket (proc, xdr_arg, arg, xdr_rslt, rslt))
|
||||
return 1;
|
||||
use_keyenvoy = 1;
|
||||
}
|
||||
return key_call_keyenvoy (proc, xdr_arg, arg, xdr_rslt, rslt);
|
||||
}
|
||||
|
|
|
@ -41,6 +41,7 @@
|
|||
#include <sys/types.h>
|
||||
#include <rpc/types.h>
|
||||
#include <rpc/auth.h>
|
||||
#include <sys/un.h>
|
||||
|
||||
__BEGIN_DECLS
|
||||
|
||||
|
@ -282,7 +283,8 @@ extern CLIENT *clntraw_create __P ((__const u_long __prog,
|
|||
|
||||
|
||||
/*
|
||||
* Generic client creation routine. Supported protocols are "udp" and "tcp"
|
||||
* Generic client creation routine. Supported protocols are "udp", "tcp" and
|
||||
* "unix"
|
||||
* CLIENT *
|
||||
* clnt_create(host, prog, vers, prot)
|
||||
* char *host; -- hostname
|
||||
|
@ -341,6 +343,24 @@ extern CLIENT *clntudp_bufcreate __P ((struct sockaddr_in *__raddr,
|
|||
int *__sockp, u_int __sendsz,
|
||||
u_int __recvsz));
|
||||
|
||||
|
||||
/*
|
||||
* AF_UNIX based rpc
|
||||
* CLIENT *
|
||||
* clntunix_create(raddr, prog, vers, sockp, sendsz, recvsz)
|
||||
* struct sockaddr_un *raddr;
|
||||
* u_long prog;
|
||||
* u_long version;
|
||||
* register int *sockp;
|
||||
* u_int sendsz;
|
||||
* u_int recvsz;
|
||||
*/
|
||||
extern CLIENT *clntunix_create __P ((struct sockaddr_un *__raddr,
|
||||
u_long __program, u_long __version,
|
||||
int *__sockp, u_int __sendsz,
|
||||
u_int __recvsz));
|
||||
|
||||
|
||||
extern int callrpc __P ((__const char *__host, __const u_long __prognum,
|
||||
__const u_long __versnum, __const u_long __procnum,
|
||||
__const xdrproc_t __inproc, __const char *__in,
|
||||
|
|
|
@ -305,6 +305,13 @@ extern SVCXPRT *svctcp_create __P ((int __sock, u_int __sendsize,
|
|||
u_int __recvsize));
|
||||
|
||||
|
||||
/*
|
||||
* Unix based rpc.
|
||||
*/
|
||||
extern SVCXPRT *svcunix_create __P ((int __sock, u_int __sendsize,
|
||||
u_int __recvsize, char *__path));
|
||||
|
||||
|
||||
__END_DECLS
|
||||
|
||||
#endif /* rpc/svc.h */
|
||||
|
|
|
@ -120,8 +120,22 @@ _svcauth_unix (struct svc_req *rqst, struct rpc_msg *msg)
|
|||
stat = AUTH_BADCRED;
|
||||
goto done;
|
||||
}
|
||||
rqst->rq_xprt->xp_verf.oa_flavor = AUTH_NULL;
|
||||
rqst->rq_xprt->xp_verf.oa_length = 0;
|
||||
|
||||
/* get the verifier */
|
||||
if ((u_int)msg->rm_call.cb_verf.oa_length)
|
||||
{
|
||||
rqst->rq_xprt->xp_verf.oa_flavor =
|
||||
msg->rm_call.cb_verf.oa_flavor;
|
||||
rqst->rq_xprt->xp_verf.oa_base =
|
||||
msg->rm_call.cb_verf.oa_base;
|
||||
rqst->rq_xprt->xp_verf.oa_length =
|
||||
msg->rm_call.cb_verf.oa_length;
|
||||
}
|
||||
else
|
||||
{
|
||||
rqst->rq_xprt->xp_verf.oa_flavor = AUTH_NULL;
|
||||
rqst->rq_xprt->xp_verf.oa_length = 0;
|
||||
}
|
||||
stat = AUTH_OK;
|
||||
done:
|
||||
XDR_DESTROY (&xdrs);
|
||||
|
|
|
@ -141,7 +141,7 @@ svctcp_create (int sock, u_int sendsize, u_int recvsize)
|
|||
{
|
||||
if ((sock = __socket (AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0)
|
||||
{
|
||||
perror (_("svctcp_.c - udp socket creation problem"));
|
||||
perror (_("svc_tcp.c - tcp socket creation problem"));
|
||||
return (SVCXPRT *) NULL;
|
||||
}
|
||||
madesock = TRUE;
|
||||
|
@ -156,7 +156,7 @@ svctcp_create (int sock, u_int sendsize, u_int recvsize)
|
|||
if ((getsockname (sock, (struct sockaddr *) &addr, &len) != 0) ||
|
||||
(listen (sock, 2) != 0))
|
||||
{
|
||||
perror (_("svctcp_.c - cannot getsockname or listen"));
|
||||
perror (_("svc_tcp.c - cannot getsockname or listen"));
|
||||
if (madesock)
|
||||
(void) __close (sock);
|
||||
return (SVCXPRT *) NULL;
|
||||
|
|
|
@ -0,0 +1,496 @@
|
|||
/*
|
||||
* 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_unix.c, Server side for TCP/IP based RPC.
|
||||
*
|
||||
* Copyright (C) 1984, Sun Microsystems, Inc.
|
||||
*
|
||||
* Actually implements two flavors of transporter -
|
||||
* a unix rendezvouser (a listener and connection establisher)
|
||||
* and a record/unix stream.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <rpc/rpc.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/uio.h>
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
/*
|
||||
* Ops vector for AF_UNIX based rpc service handle
|
||||
*/
|
||||
static bool_t svcunix_recv (SVCXPRT *, struct rpc_msg *);
|
||||
static enum xprt_stat svcunix_stat (SVCXPRT *);
|
||||
static bool_t svcunix_getargs (SVCXPRT *, xdrproc_t, caddr_t);
|
||||
static bool_t svcunix_reply (SVCXPRT *, struct rpc_msg *);
|
||||
static bool_t svcunix_freeargs (SVCXPRT *, xdrproc_t, caddr_t);
|
||||
static void svcunix_destroy (SVCXPRT *);
|
||||
|
||||
static const struct xp_ops svcunix_op =
|
||||
{
|
||||
svcunix_recv,
|
||||
svcunix_stat,
|
||||
svcunix_getargs,
|
||||
svcunix_reply,
|
||||
svcunix_freeargs,
|
||||
svcunix_destroy
|
||||
};
|
||||
|
||||
/*
|
||||
* Ops vector for AF_UNIX rendezvous handler
|
||||
*/
|
||||
static bool_t rendezvous_request (SVCXPRT *, struct rpc_msg *);
|
||||
static enum xprt_stat rendezvous_stat (SVCXPRT *);
|
||||
|
||||
static const struct xp_ops svcunix_rendezvous_op =
|
||||
{
|
||||
rendezvous_request,
|
||||
rendezvous_stat,
|
||||
(bool_t (*) (SVCXPRT *, xdrproc_t, caddr_t)) abort,
|
||||
(bool_t (*) (SVCXPRT *, struct rpc_msg *)) abort,
|
||||
(bool_t (*) (SVCXPRT *, xdrproc_t, caddr_t)) abort,
|
||||
svcunix_destroy
|
||||
};
|
||||
|
||||
static int readunix (char*, char *, int);
|
||||
static int writeunix (char *, char *, int);
|
||||
static SVCXPRT *makefd_xprt (int, u_int, u_int) internal_function;
|
||||
|
||||
struct unix_rendezvous { /* kept in xprt->xp_p1 */
|
||||
u_int sendsize;
|
||||
u_int recvsize;
|
||||
};
|
||||
|
||||
struct unix_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 = svcunix_create(sock, send_buf_size, recv_buf_size);
|
||||
*
|
||||
* Creates, registers, and returns a (rpc) unix 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 svcunix_create
|
||||
* binds it to an arbitrary port. The routine then starts a unix
|
||||
* 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 unix 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 *
|
||||
svcunix_create (int sock, u_int sendsize, u_int recvsize, char *path)
|
||||
{
|
||||
bool_t madesock = FALSE;
|
||||
SVCXPRT *xprt;
|
||||
struct unix_rendezvous *r;
|
||||
struct sockaddr_un addr;
|
||||
socklen_t len = sizeof (struct sockaddr_in);
|
||||
|
||||
if (sock == RPC_ANYSOCK)
|
||||
{
|
||||
if ((sock = __socket (AF_UNIX, SOCK_STREAM, 0)) < 0)
|
||||
{
|
||||
perror (_("svc_unix.c - AF_UNIX socket creation problem"));
|
||||
return (SVCXPRT *) NULL;
|
||||
}
|
||||
madesock = TRUE;
|
||||
}
|
||||
memset (&addr, '\0', sizeof (addr));
|
||||
addr.sun_family = AF_UNIX;
|
||||
len = strlen (addr.sun_path) + 1;
|
||||
memcpy (addr.sun_path, path, len);
|
||||
len += sizeof (addr.sun_family);
|
||||
|
||||
bind (sock, (struct sockaddr *) &addr, len);
|
||||
|
||||
if (getsockname (sock, (struct sockaddr *) &addr, &len) != 0
|
||||
|| listen (sock, 2) != 0)
|
||||
{
|
||||
perror (_("svc_unix.c - cannot getsockname or listen"));
|
||||
if (madesock)
|
||||
__close (sock);
|
||||
return (SVCXPRT *) NULL;
|
||||
}
|
||||
|
||||
r = (struct unix_rendezvous *) mem_alloc (sizeof (*r));
|
||||
if (r == NULL)
|
||||
{
|
||||
fputs (_("svcunix_create: out of memory\n"), stderr);
|
||||
return NULL;
|
||||
}
|
||||
r->sendsize = sendsize;
|
||||
r->recvsize = recvsize;
|
||||
xprt = (SVCXPRT *) mem_alloc (sizeof (SVCXPRT));
|
||||
if (xprt == NULL)
|
||||
{
|
||||
fputs (_("svcunix_create: out of memory\n"), stderr);
|
||||
return NULL;
|
||||
}
|
||||
xprt->xp_p2 = NULL;
|
||||
xprt->xp_p1 = (caddr_t) r;
|
||||
xprt->xp_verf = _null_auth;
|
||||
xprt->xp_ops = &svcunix_rendezvous_op;
|
||||
xprt->xp_port = -1;
|
||||
xprt->xp_sock = sock;
|
||||
xprt_register (xprt);
|
||||
return xprt;
|
||||
}
|
||||
|
||||
/*
|
||||
* Like svunix_create(), except the routine takes any *open* UNIX file
|
||||
* descriptor as its first input.
|
||||
*/
|
||||
SVCXPRT *
|
||||
svcunixfd_create (int fd, u_int sendsize, u_int recvsize)
|
||||
{
|
||||
return makefd_xprt (fd, sendsize, recvsize);
|
||||
}
|
||||
|
||||
static SVCXPRT *
|
||||
internal_function
|
||||
makefd_xprt (int fd, u_int sendsize, u_int recvsize)
|
||||
{
|
||||
SVCXPRT *xprt;
|
||||
struct unix_conn *cd;
|
||||
|
||||
xprt = (SVCXPRT *) mem_alloc (sizeof (SVCXPRT));
|
||||
if (xprt == (SVCXPRT *) NULL)
|
||||
{
|
||||
(void) fputs (_("svc_unix: makefd_xprt: out of memory\n"), stderr);
|
||||
goto done;
|
||||
}
|
||||
cd = (struct unix_conn *) mem_alloc (sizeof (struct unix_conn));
|
||||
if (cd == (struct unix_conn *) NULL)
|
||||
{
|
||||
(void) fputs (_("svc_unix: makefd_xprt: out of memory\n"), stderr);
|
||||
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, readunix, writeunix);
|
||||
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 = &svcunix_op; /* truly 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 (SVCXPRT *xprt, struct rpc_msg *errmsg)
|
||||
{
|
||||
int sock;
|
||||
struct unix_rendezvous *r;
|
||||
struct sockaddr_un addr;
|
||||
struct sockaddr_in in_addr;
|
||||
socklen_t len;
|
||||
|
||||
r = (struct unix_rendezvous *) xprt->xp_p1;
|
||||
again:
|
||||
len = sizeof (struct sockaddr_un);
|
||||
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)
|
||||
*/
|
||||
memset (&in_addr, '\0', sizeof (in_addr));
|
||||
in_addr.sin_family = AF_UNIX;
|
||||
xprt = makefd_xprt (sock, r->sendsize, r->recvsize);
|
||||
xprt->xp_raddr = in_addr;
|
||||
xprt->xp_addrlen = len;
|
||||
return FALSE; /* there is never an rpc msg to be processed */
|
||||
}
|
||||
|
||||
static enum xprt_stat
|
||||
rendezvous_stat (SVCXPRT *xprt)
|
||||
{
|
||||
return XPRT_IDLE;
|
||||
}
|
||||
|
||||
static void
|
||||
svcunix_destroy (SVCXPRT *xprt)
|
||||
{
|
||||
struct unix_conn *cd = (struct unix_conn *) xprt->xp_p1;
|
||||
|
||||
xprt_unregister (xprt);
|
||||
__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 unix_conn));
|
||||
mem_free ((caddr_t) xprt, sizeof (SVCXPRT));
|
||||
}
|
||||
|
||||
struct cmessage {
|
||||
struct cmsghdr cmsg;
|
||||
struct cmsgcred cmcred;
|
||||
};
|
||||
|
||||
/* XXX This is not thread safe, but since the main functions in svc.c
|
||||
and the rpcgen generated *_svc functions for the daemon are also not
|
||||
thread safe and uses static global variables, it doesn't matter. */
|
||||
static struct cmessage cm;
|
||||
|
||||
static int
|
||||
__msgread (int sock, void *buf, size_t cnt)
|
||||
{
|
||||
struct iovec iov[1];
|
||||
struct msghdr msg;
|
||||
int len, on = 1;
|
||||
|
||||
iov[0].iov_base = buf;
|
||||
iov[0].iov_len = cnt;
|
||||
|
||||
msg.msg_iov = iov;
|
||||
msg.msg_iovlen = 1;
|
||||
msg.msg_name = NULL;
|
||||
msg.msg_namelen = 0;
|
||||
msg.msg_control = (caddr_t) &cm;
|
||||
msg.msg_controllen = sizeof (struct cmessage);
|
||||
msg.msg_flags = 0;
|
||||
|
||||
setsockopt (sock, SOL_SOCKET, SO_PASSCRED, &on, sizeof (on));
|
||||
|
||||
return recvmsg (sock, &msg, 0);
|
||||
}
|
||||
|
||||
static int
|
||||
__msgwrite (int sock, void *buf, size_t cnt)
|
||||
{
|
||||
#ifndef SCM_CRED
|
||||
/* We cannot implement this reliably. */
|
||||
__set_errno (ENOSYS);
|
||||
#else
|
||||
struct iovec iov[1];
|
||||
struct msghdr msg;
|
||||
int len;
|
||||
|
||||
iov[0].iov_base = buf;
|
||||
iov[0].iov_len = cnt;
|
||||
|
||||
cm.cmsg.cmsg_type = SCM_CREDS;
|
||||
cm.cmsg.cmsg_level = SOL_SOCKET;
|
||||
cm.cmsg.cmsg_len = sizeof (struct cmessage);
|
||||
/* XXX I'm not sure, if we really should use gete?id(), or get?id().
|
||||
It would be much better, if the kernel could pass both to the
|
||||
client. */
|
||||
cm.cmcred.cmcred_pid = __getpid ();
|
||||
cm.cmcred.cmcred_uid = __geteuid ();
|
||||
cm.cmcred.cmcred_gid = __getegid ();
|
||||
|
||||
msg.msg_iov = iov;
|
||||
msg.msg_iovlen = 1;
|
||||
msg.msg_name = NULL;
|
||||
msg.msg_namelen = 0;
|
||||
msg.msg_control = (caddr_t) &cm;
|
||||
msg.msg_controllen = sizeof (struct cmessage);
|
||||
msg.msg_flags = 0;
|
||||
|
||||
return sendmsg (sock, &msg, 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* 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 unix connection.
|
||||
* any error is fatal and the connection is closed.
|
||||
* (And a read of zero bytes is a half closed stream => error.)
|
||||
*/
|
||||
static int
|
||||
readunix (char *xprtptr, char *buf, int len)
|
||||
{
|
||||
SVCXPRT *xprt = (SVCXPRT *) xprtptr;
|
||||
int sock = xprt->xp_sock;
|
||||
#ifdef FD_SETSIZE
|
||||
fd_set readfds;
|
||||
#else
|
||||
int mask = 1 << sock;
|
||||
int readfds;
|
||||
#endif /* def FD_SETSIZE */
|
||||
while (1)
|
||||
{
|
||||
struct timeval timeout = wait_per_try;
|
||||
readfds = svc_fdset;
|
||||
#ifdef FD_SETSIZE
|
||||
FD_SET (sock, &readfds);
|
||||
#else
|
||||
readfds |= (1 << sock);
|
||||
#endif /* def FD_SETSIZE */
|
||||
if (__select (_rpc_dtablesize (), &readfds, (fd_set *) NULL,
|
||||
(fd_set *) NULL, &timeout) <= 0)
|
||||
{
|
||||
if (errno == EINTR)
|
||||
continue;
|
||||
goto fatal_err;
|
||||
}
|
||||
|
||||
#ifdef FD_SETSIZE
|
||||
if (FD_ISSET (sock, &readfds))
|
||||
#else
|
||||
if (readfds == mask)
|
||||
#endif /* def FD_SETSIZE */
|
||||
break;
|
||||
|
||||
svc_getreqset (&readfds);
|
||||
}
|
||||
|
||||
if ((len = __msgread (sock, buf, len)) > 0)
|
||||
return len;
|
||||
|
||||
fatal_err:
|
||||
((struct unix_conn *) (xprt->xp_p1))->strm_stat = XPRT_DIED;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* writes data to the unix connection.
|
||||
* Any error is fatal and the connection is closed.
|
||||
*/
|
||||
static int
|
||||
writeunix (char *xprtptr, char * buf, int len)
|
||||
{
|
||||
SVCXPRT *xprt = (SVCXPRT *) xprtptr;
|
||||
int i, cnt;
|
||||
|
||||
for (cnt = len; cnt > 0; cnt -= i, buf += i)
|
||||
{
|
||||
if ((i = __msgwrite (xprt->xp_sock, buf, cnt)) < 0)
|
||||
{
|
||||
((struct unix_conn *) (xprt->xp_p1))->strm_stat = XPRT_DIED;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
||||
static enum xprt_stat
|
||||
svcunix_stat (SVCXPRT *xprt)
|
||||
{
|
||||
struct unix_conn *cd =
|
||||
(struct unix_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
|
||||
svcunix_recv (SVCXPRT *xprt, struct rpc_msg *msg)
|
||||
{
|
||||
struct unix_conn *cd = (struct unix_conn *) (xprt->xp_p1);
|
||||
XDR *xdrs = &(cd->xdrs);
|
||||
|
||||
xdrs->x_op = XDR_DECODE;
|
||||
xdrrec_skiprecord (xdrs);
|
||||
if (xdr_callmsg (xdrs, msg))
|
||||
{
|
||||
cd->x_id = msg->rm_xid;
|
||||
/* set up verifiers */
|
||||
msg->rm_call.cb_verf.oa_flavor = AUTH_UNIX;
|
||||
msg->rm_call.cb_verf.oa_base = (caddr_t) &cm;
|
||||
msg->rm_call.cb_verf.oa_length = sizeof (cm);
|
||||
return TRUE;
|
||||
}
|
||||
cd->strm_stat = XPRT_DIED; /* XXXX */
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static bool_t
|
||||
svcunix_getargs (SVCXPRT *xprt, xdrproc_t xdr_args, caddr_t args_ptr)
|
||||
{
|
||||
return (*xdr_args) (&(((struct unix_conn *) (xprt->xp_p1))->xdrs),
|
||||
args_ptr);
|
||||
}
|
||||
|
||||
static bool_t
|
||||
svcunix_freeargs (xprt, xdr_args, args_ptr)
|
||||
SVCXPRT *xprt;
|
||||
xdrproc_t xdr_args;
|
||||
caddr_t args_ptr;
|
||||
{
|
||||
XDR *xdrs = &(((struct unix_conn *) (xprt->xp_p1))->xdrs);
|
||||
|
||||
xdrs->x_op = XDR_FREE;
|
||||
return (*xdr_args) (xdrs, args_ptr);
|
||||
}
|
||||
|
||||
static bool_t
|
||||
svcunix_reply (xprt, msg)
|
||||
SVCXPRT *xprt;
|
||||
struct rpc_msg *msg;
|
||||
{
|
||||
struct unix_conn *cd = (struct unix_conn *) (xprt->xp_p1);
|
||||
XDR *xdrs = &(cd->xdrs);
|
||||
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;
|
||||
}
|
|
@ -808,26 +808,29 @@ glob (pattern, flags, errfunc, pglob)
|
|||
|
||||
flags |= GLOB_MAGCHAR;
|
||||
|
||||
/* We have ignored the GLOB_NOCHECK flag in the `glob_in_dir' calls.
|
||||
But if we have not found any matching entry and thie GLOB_NOCHECK
|
||||
flag was set we must return the list consisting of the disrectory
|
||||
names followed by the filename. */
|
||||
if (pglob->gl_pathc == oldcount)
|
||||
/* No matches. */
|
||||
if (flags & GLOB_NOCHECK)
|
||||
{
|
||||
size_t len = strlen (pattern) + 1;
|
||||
char *patcopy = (char *) malloc (len);
|
||||
if (patcopy == NULL)
|
||||
return GLOB_NOSPACE;
|
||||
memcpy (patcopy, pattern, len);
|
||||
size_t filename_len = strlen (filename) + 1;
|
||||
char **new_pathv;
|
||||
struct stat st;
|
||||
|
||||
/* This is an pessimistic guess about the size. */
|
||||
pglob->gl_pathv
|
||||
= (char **) realloc (pglob->gl_pathv,
|
||||
(pglob->gl_pathc +
|
||||
((flags & GLOB_DOOFFS) ?
|
||||
pglob->gl_offs : 0) +
|
||||
1 + 1) *
|
||||
dirs.gl_pathc + 1) *
|
||||
sizeof (char *));
|
||||
if (pglob->gl_pathv == NULL)
|
||||
{
|
||||
free (patcopy);
|
||||
globfree (&dirs);
|
||||
return GLOB_NOSPACE;
|
||||
}
|
||||
|
||||
|
@ -835,12 +838,54 @@ glob (pattern, flags, errfunc, pglob)
|
|||
while (pglob->gl_pathc < pglob->gl_offs)
|
||||
pglob->gl_pathv[pglob->gl_pathc++] = NULL;
|
||||
|
||||
pglob->gl_pathv[pglob->gl_pathc++] = patcopy;
|
||||
for (i = 0; i < dirs.gl_pathc; ++i)
|
||||
{
|
||||
const char *dir = dirs.gl_pathv[i];
|
||||
size_t dir_len = strlen (dir);
|
||||
|
||||
/* First check whether this really is a directory. */
|
||||
if (((flags & GLOB_ALTDIRFUNC)
|
||||
? (*pglob->gl_stat) (dir, &st) : __stat (dir, &st)) != 0
|
||||
|| !S_ISDIR (st.st_mode))
|
||||
/* No directory, ignore this entry. */
|
||||
continue;
|
||||
|
||||
pglob->gl_pathv[pglob->gl_pathc] = malloc (dir_len + 1
|
||||
+ filename_len);
|
||||
if (pglob->gl_pathv[pglob->gl_pathc] == NULL)
|
||||
{
|
||||
globfree (&dirs);
|
||||
globfree (pglob);
|
||||
return GLOB_NOSPACE;
|
||||
}
|
||||
|
||||
#ifdef HAVE_MEMPCPY
|
||||
mempcpy (mempcpy (mempcpy (pglob->gl_pathv[pglob->gl_pathc],
|
||||
dir, dir_len),
|
||||
"/", 1),
|
||||
filename, filename_len);
|
||||
#else
|
||||
memcpy (pglob->gl_pathv[pglob->gl_pathc], dir, dir_len);
|
||||
pglob->gl_pathv[pglob->gl_pathc][dir_len] = '/';
|
||||
memcpy (&pglob->gl_pathv[pglob->gl_pathc][dir_len + 1],
|
||||
filename, filename_len);
|
||||
#endif
|
||||
++pglob->gl_pathc;
|
||||
}
|
||||
|
||||
pglob->gl_pathv[pglob->gl_pathc] = NULL;
|
||||
pglob->gl_flags = flags;
|
||||
|
||||
/* Now we know how large the gl_pathv vector must be. */
|
||||
new_pathv = realloc (pglob->gl_pathv,
|
||||
(pglob->gl_pathc + 1) * sizeof (char *));
|
||||
if (new_pathv != NULL)
|
||||
pglob->gl_pathv = new_pathv;
|
||||
}
|
||||
else
|
||||
return GLOB_NOMATCH;
|
||||
|
||||
globfree (&dirs);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
@ -77,8 +77,8 @@ static double zero = 0.0; /* used as const */
|
|||
* 37-- y1(x>X_TLOSS)
|
||||
* 38-- jn(|x|>X_TLOSS, n)
|
||||
* 39-- yn(x>X_TLOSS, n)
|
||||
* 40-- gamma(finite) overflow
|
||||
* 41-- gamma(-integer)
|
||||
* 40-- tgamma(finite) overflow
|
||||
* 41-- tgamma(-integer)
|
||||
* 42-- pow(NaN,0.0)
|
||||
* 43-- +0**neg
|
||||
* 44-- exp2 overflow
|
||||
|
@ -829,8 +829,8 @@ static double zero = 0.0; /* used as const */
|
|||
case 240:
|
||||
/* gamma(finite) overflow */
|
||||
exc.type = OVERFLOW;
|
||||
exc.name = type < 100 ? "gamma" : (type < 200
|
||||
? "gammaf" : "gammal");
|
||||
exc.name = type < 100 ? "tgamma" : (type < 200
|
||||
? "tgammaf" : "tgammal");
|
||||
exc.retval = HUGE_VAL;
|
||||
if (_LIB_VERSION == _POSIX_)
|
||||
__set_errno (ERANGE);
|
||||
|
@ -843,14 +843,14 @@ static double zero = 0.0; /* used as const */
|
|||
case 241:
|
||||
/* gamma(-integer) or gamma(0) */
|
||||
exc.type = SING;
|
||||
exc.name = type < 100 ? "gamma" : (type < 200
|
||||
? "gammaf" : "gammal");
|
||||
exc.name = type < 100 ? "tgamma" : (type < 200
|
||||
? "tgammaf" : "tgammal");
|
||||
exc.retval = NAN;
|
||||
if (_LIB_VERSION == _POSIX_)
|
||||
__set_errno (EDOM);
|
||||
else if (!matherr(&exc)) {
|
||||
if (_LIB_VERSION == _SVID_) {
|
||||
(void) WRITE2("gamma: SING error\n", 18);
|
||||
(void) WRITE2("tgamma: SING error\n", 18);
|
||||
exc.retval = HUGE_VAL;
|
||||
}
|
||||
__set_errno (EDOM);
|
||||
|
|
|
@ -1,68 +0,0 @@
|
|||
/* w_gammaf.c -- float version of w_gamma.c.
|
||||
* Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com.
|
||||
*/
|
||||
|
||||
/*
|
||||
* ====================================================
|
||||
* Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
|
||||
*
|
||||
* Developed at SunPro, a Sun Microsystems, Inc. business.
|
||||
* Permission to use, copy, modify, and distribute this
|
||||
* software is freely granted, provided that this notice
|
||||
* is preserved.
|
||||
* ====================================================
|
||||
*/
|
||||
|
||||
#if defined(LIBM_SCCS) && !defined(lint)
|
||||
static char rcsid[] = "$NetBSD: w_gammaf.c,v 1.4 1995/11/20 22:06:48 jtc Exp $";
|
||||
#endif
|
||||
|
||||
#include "math.h"
|
||||
#include "math_private.h"
|
||||
|
||||
#ifdef __STDC__
|
||||
float __gammaf(float x)
|
||||
#else
|
||||
float __gammaf(x)
|
||||
float x;
|
||||
#endif
|
||||
{
|
||||
float y;
|
||||
#ifndef _IEEE_LIBM
|
||||
if (_LIB_VERSION == _SVID_)
|
||||
{
|
||||
y = __ieee754_lgammaf_r(x,&signgam);
|
||||
|
||||
if(!__finitef(y)&&__finitef(x)) {
|
||||
if(__floorf(x)==x&&x<=(float)0.0)
|
||||
/* lgammaf pole */
|
||||
return (float)__kernel_standard((double)x,(double)x,115);
|
||||
else
|
||||
/* lgammaf overflow */
|
||||
return (float)__kernel_standard((double)x,(double)x,114);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
#endif
|
||||
int local_signgam;
|
||||
y = __ieee754_gammaf_r(x,&local_signgam);
|
||||
if (local_signgam < 0) y = -y;
|
||||
#ifdef _IEEE_LIBM
|
||||
return y;
|
||||
#else
|
||||
if(_LIB_VERSION == _IEEE_) return y;
|
||||
|
||||
if(!__finitef(y)&&__finitef(x)) {
|
||||
if(__floorf(x)==x&&x<=(float)0.0)
|
||||
/* gammaf pole */
|
||||
return (float)__kernel_standard((double)x,(double)x,141);
|
||||
else
|
||||
/* gammaf overflow */
|
||||
return (float)__kernel_standard((double)x,(double)x,140);
|
||||
}
|
||||
}
|
||||
return y;
|
||||
#endif
|
||||
}
|
||||
weak_alias (__gammaf, gammaf)
|
|
@ -1,71 +0,0 @@
|
|||
/* w_gammal.c -- long double version of w_gamma.c.
|
||||
* Conversion to long double by Ulrich Drepper,
|
||||
* Cygnus Support, drepper@cygnus.com.
|
||||
*/
|
||||
|
||||
/*
|
||||
* ====================================================
|
||||
* Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
|
||||
*
|
||||
* Developed at SunPro, a Sun Microsystems, Inc. business.
|
||||
* Permission to use, copy, modify, and distribute this
|
||||
* software is freely granted, provided that this notice
|
||||
* is preserved.
|
||||
* ====================================================
|
||||
*/
|
||||
|
||||
#if defined(LIBM_SCCS) && !defined(lint)
|
||||
static char rcsid[] = "$NetBSD: $";
|
||||
#endif
|
||||
|
||||
/* long double gammal(double x)
|
||||
* Return the Gamma function of x.
|
||||
*/
|
||||
|
||||
#include "math.h"
|
||||
#include "math_private.h"
|
||||
|
||||
#ifdef __STDC__
|
||||
long double __gammal(long double x)
|
||||
#else
|
||||
long double __gammal(x)
|
||||
long double x;
|
||||
#endif
|
||||
{
|
||||
long double y;
|
||||
#ifndef _IEEE_LIBM
|
||||
if (_LIB_VERSION == _SVID_)
|
||||
{
|
||||
y = __ieee754_lgammal_r(x,&signgam);
|
||||
|
||||
if(!__finitel(y)&&__finitel(x)) {
|
||||
if(__floorl(x)==x&&x<=(long double)0.0)
|
||||
/* lgamma pole */
|
||||
return (long double)__kernel_standard((double)x,(double)x,15);
|
||||
else
|
||||
/* lgamma overflow */
|
||||
return (long double)__kernel_standard((double)x,(double)x,14);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
#endif
|
||||
int local_signgam;
|
||||
y = __ieee754_gammal_r(x,&local_signgam);
|
||||
if (local_signgam < 0) y = -y;
|
||||
#ifdef _IEEE_LIBM
|
||||
return y;
|
||||
#else
|
||||
if(_LIB_VERSION == _IEEE_) return y;
|
||||
|
||||
if(!__finitel(y)&&__finitel(x)) {
|
||||
if(__floorl(x)==x&&x<=0.0)
|
||||
return __kernel_standard(x,x,241); /* gamma pole */
|
||||
else
|
||||
return __kernel_standard(x,x,240); /* gamma overflow */
|
||||
}
|
||||
}
|
||||
return y;
|
||||
#endif
|
||||
}
|
||||
weak_alias (__gammal, gammal)
|
|
@ -50,7 +50,11 @@ static char rcsid[] = "$NetBSD: w_lgamma.c,v 1.6 1995/05/10 20:49:24 jtc Exp $";
|
|||
#endif
|
||||
}
|
||||
weak_alias (__lgamma, lgamma)
|
||||
strong_alias (__lgamma, __gamma)
|
||||
weak_alias (__gamma, gamma)
|
||||
#ifdef NO_LONG_DOUBLE
|
||||
strong_alias (__lgamma, __lgammal)
|
||||
weak_alias (__lgamma, lgammal)
|
||||
strong_alias (__gamma, __gammal)
|
||||
weak_alias (__gamma, gammal)
|
||||
#endif
|
||||
|
|
|
@ -49,3 +49,5 @@ static char rcsid[] = "$NetBSD: w_lgammaf.c,v 1.3 1995/05/10 20:49:30 jtc Exp $"
|
|||
#endif
|
||||
}
|
||||
weak_alias (__lgammaf, lgammaf)
|
||||
strong_alias (__lgammaf, __gammaf)
|
||||
weak_alias (__gammaf, gammaf)
|
||||
|
|
|
@ -54,3 +54,5 @@ static char rcsid[] = "$NetBSD: $";
|
|||
#endif
|
||||
}
|
||||
weak_alias (__lgammal, lgammal)
|
||||
strong_alias (__lgammal, __gammal)
|
||||
weak_alias (__gammal, gammal)
|
||||
|
|
|
@ -23,50 +23,32 @@ static char rcsid[] = "$NetBSD: w_gamma.c,v 1.7 1995/11/20 22:06:43 jtc Exp $";
|
|||
#include "math_private.h"
|
||||
|
||||
#ifdef __STDC__
|
||||
double __gamma(double x)
|
||||
double __tgamma(double x)
|
||||
#else
|
||||
double __gamma(x)
|
||||
double __tgamma(x)
|
||||
double x;
|
||||
#endif
|
||||
{
|
||||
double y;
|
||||
#ifndef _IEEE_LIBM
|
||||
if (_LIB_VERSION == _SVID_)
|
||||
{
|
||||
y = __ieee754_lgamma_r(x,&signgam);
|
||||
|
||||
if(!__finite(y)&&__finite(x)) {
|
||||
if(__floor(x)==x&&x<=(double)0.0)
|
||||
/* lgamma pole */
|
||||
return __kernel_standard(x,x,15);
|
||||
else
|
||||
/* lgamma overflow */
|
||||
return __kernel_standard(x,x,14);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
#endif
|
||||
int local_signgam;
|
||||
y = __ieee754_gamma_r(x,&local_signgam);
|
||||
if (local_signgam < 0) y = -y;
|
||||
int local_signgam;
|
||||
y = __ieee754_gamma_r(x,&local_signgam);
|
||||
if (local_signgam < 0) y = -y;
|
||||
#ifdef _IEEE_LIBM
|
||||
return y;
|
||||
return y;
|
||||
#else
|
||||
if(_LIB_VERSION == _IEEE_) return y;
|
||||
if(_LIB_VERSION == _IEEE_) return y;
|
||||
|
||||
if(!__finite(y)&&__finite(x)) {
|
||||
if(__floor(x)==x&&x<=0.0)
|
||||
return __kernel_standard(x,x,41); /* gamma pole */
|
||||
else
|
||||
return __kernel_standard(x,x,40); /* gamma overflow */
|
||||
}
|
||||
}
|
||||
if(!__finite(y)&&__finite(x)) {
|
||||
if(__floor(x)==x&&x<=0.0)
|
||||
return __kernel_standard(x,x,41); /* tgamma pole */
|
||||
else
|
||||
return __kernel_standard(x,x,40); /* tgamma overflow */
|
||||
}
|
||||
return y;
|
||||
#endif
|
||||
}
|
||||
weak_alias (__gamma, gamma)
|
||||
weak_alias (__tgamma, tgamma)
|
||||
#ifdef NO_LONG_DOUBLE
|
||||
strong_alias (__gamma, __gammal)
|
||||
weak_alias (__gamma, gammal)
|
||||
strong_alias (__tgamma, __tgammal)
|
||||
weak_alias (__tgamma, tgammal)
|
||||
#endif
|
|
@ -0,0 +1,50 @@
|
|||
/* w_gammaf.c -- float version of w_gamma.c.
|
||||
* Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com.
|
||||
*/
|
||||
|
||||
/*
|
||||
* ====================================================
|
||||
* Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
|
||||
*
|
||||
* Developed at SunPro, a Sun Microsystems, Inc. business.
|
||||
* Permission to use, copy, modify, and distribute this
|
||||
* software is freely granted, provided that this notice
|
||||
* is preserved.
|
||||
* ====================================================
|
||||
*/
|
||||
|
||||
#if defined(LIBM_SCCS) && !defined(lint)
|
||||
static char rcsid[] = "$NetBSD: w_gammaf.c,v 1.4 1995/11/20 22:06:48 jtc Exp $";
|
||||
#endif
|
||||
|
||||
#include "math.h"
|
||||
#include "math_private.h"
|
||||
|
||||
#ifdef __STDC__
|
||||
float __tgammaf(float x)
|
||||
#else
|
||||
float __tgammaf(x)
|
||||
float x;
|
||||
#endif
|
||||
{
|
||||
float y;
|
||||
int local_signgam;
|
||||
y = __ieee754_gammaf_r(x,&local_signgam);
|
||||
if (local_signgam < 0) y = -y;
|
||||
#ifdef _IEEE_LIBM
|
||||
return y;
|
||||
#else
|
||||
if(_LIB_VERSION == _IEEE_) return y;
|
||||
|
||||
if(!__finitef(y)&&__finitef(x)) {
|
||||
if(__floorf(x)==x&&x<=(float)0.0)
|
||||
/* tgammaf pole */
|
||||
return (float)__kernel_standard((double)x,(double)x,141);
|
||||
else
|
||||
/* tgammaf overflow */
|
||||
return (float)__kernel_standard((double)x,(double)x,140);
|
||||
}
|
||||
return y;
|
||||
#endif
|
||||
}
|
||||
weak_alias (__tgammaf, tgammaf)
|
|
@ -0,0 +1,53 @@
|
|||
/* w_gammal.c -- long double version of w_gamma.c.
|
||||
* Conversion to long double by Ulrich Drepper,
|
||||
* Cygnus Support, drepper@cygnus.com.
|
||||
*/
|
||||
|
||||
/*
|
||||
* ====================================================
|
||||
* Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
|
||||
*
|
||||
* Developed at SunPro, a Sun Microsystems, Inc. business.
|
||||
* Permission to use, copy, modify, and distribute this
|
||||
* software is freely granted, provided that this notice
|
||||
* is preserved.
|
||||
* ====================================================
|
||||
*/
|
||||
|
||||
#if defined(LIBM_SCCS) && !defined(lint)
|
||||
static char rcsid[] = "$NetBSD: $";
|
||||
#endif
|
||||
|
||||
/* long double gammal(double x)
|
||||
* Return the Gamma function of x.
|
||||
*/
|
||||
|
||||
#include "math.h"
|
||||
#include "math_private.h"
|
||||
|
||||
#ifdef __STDC__
|
||||
long double __tgammal(long double x)
|
||||
#else
|
||||
long double __tgammal(x)
|
||||
long double x;
|
||||
#endif
|
||||
{
|
||||
long double y;
|
||||
int local_signgam;
|
||||
y = __ieee754_gammal_r(x,&local_signgam);
|
||||
if (local_signgam < 0) y = -y;
|
||||
#ifdef _IEEE_LIBM
|
||||
return y;
|
||||
#else
|
||||
if(_LIB_VERSION == _IEEE_) return y;
|
||||
|
||||
if(!__finitel(y)&&__finitel(x)) {
|
||||
if(__floorl(x)==x&&x<=0.0)
|
||||
return __kernel_standard(x,x,241); /* tgamma pole */
|
||||
else
|
||||
return __kernel_standard(x,x,240); /* tgamma overflow */
|
||||
}
|
||||
return y;
|
||||
#endif
|
||||
}
|
||||
weak_alias (__tgammal, tgammal)
|
|
@ -240,7 +240,7 @@ open_file (const char *file_name, int mode,
|
|||
int nloops;
|
||||
error_t err;
|
||||
|
||||
assert (mode == O_RDONLY);
|
||||
assert (!(mode & ~O_READ));
|
||||
|
||||
startdir = _dl_hurd_data->portarray[file_name[0] == '/' ?
|
||||
INIT_PORT_CRDIR : INIT_PORT_CWDIR];
|
||||
|
@ -558,6 +558,38 @@ __mmap (__ptr_t addr, size_t len, int prot, int flags, int fd, off_t offset)
|
|||
return err ? (__ptr_t) __hurd_fail (err) : (__ptr_t) mapaddr;
|
||||
}
|
||||
|
||||
int weak_function
|
||||
__fxstat (int vers, int fd, struct stat *buf)
|
||||
{
|
||||
error_t err;
|
||||
|
||||
assert (vers == _STAT_VER);
|
||||
|
||||
err = __io_stat ((mach_port_t) fd, buf);
|
||||
if (err)
|
||||
return __hurd_fail (err);
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
int weak_function
|
||||
__xstat (int vers, const char *file, struct stat *buf)
|
||||
{
|
||||
error_t err;
|
||||
mach_port_t port;
|
||||
|
||||
assert (vers == _STAT_VER);
|
||||
|
||||
err = open_file (file, 0, &port, buf);
|
||||
if (err)
|
||||
return __hurd_fail (err);
|
||||
|
||||
__mach_port_deallocate (__mach_task_self (), port);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void weak_function
|
||||
_exit (int status)
|
||||
{
|
||||
|
@ -567,37 +599,6 @@ _exit (int status)
|
|||
__mach_task_self_ = (__mach_task_self) ();
|
||||
}
|
||||
|
||||
/* Read the whole contents of FILE into new mmap'd space with given
|
||||
protections. The size of the file is returned in SIZE. */
|
||||
void *
|
||||
weak_function
|
||||
_dl_sysdep_read_whole_file (const char *file, size_t *size, int prot)
|
||||
{
|
||||
struct stat stat;
|
||||
mach_port_t memobj_rd;
|
||||
void *contents;
|
||||
error_t err = open_file (file, O_RDONLY, &memobj_rd, &stat);
|
||||
|
||||
if (! err)
|
||||
{
|
||||
/* Map a copy of the file contents. */
|
||||
contents = __mmap (0, stat.st_size, prot, MAP_COPY, memobj_rd, 0);
|
||||
if (contents == (void *)-1)
|
||||
contents = 0;
|
||||
else
|
||||
*size = stat.st_size;
|
||||
|
||||
__mach_port_deallocate (__mach_task_self (), memobj_rd);
|
||||
}
|
||||
else
|
||||
{
|
||||
__hurd_fail (err);
|
||||
contents = 0;
|
||||
}
|
||||
|
||||
return contents;
|
||||
}
|
||||
|
||||
/* This function is called by interruptible RPC stubs. For initial
|
||||
dynamic linking, just use the normal mach_msg. Since this defn is
|
||||
weak, the real defn in libc.so will override it if we are linked into
|
||||
|
|
|
@ -89,5 +89,4 @@ __libc_recvmsg (int fd, struct msghdr *message, int flags)
|
|||
return ret;
|
||||
}
|
||||
|
||||
weak_alias (__libc_recvmsg, __recvmsg)
|
||||
weak_alias (__libc_recvmsg, recvmsg)
|
||||
|
|
|
@ -121,5 +121,4 @@ __libc_sendmsg (int fd, const struct msghdr *message, int flags)
|
|||
return __syscall_sendmsg (fd, message, flags);
|
||||
}
|
||||
|
||||
weak_alias (__libc_sendmsg, __sendmsg)
|
||||
weak_alias (__libc_sendmsg, sendmsg)
|
||||
|
|
Loading…
Reference in New Issue