#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <rpc/rpc.h>
#include <rpc/types.h>
#include <rpc/auth.h>
#include <rpc/clnt.h>
static char *auth_errmsg(enum auth_stat stat);
#define CLNT_PERROR_BUFLEN 256
static char buf[CLNT_PERROR_BUFLEN];
char *
clnt_sperror(CLIENT *rpch, char *s)
{
char *err, *str = buf;
struct rpc_err e;
int ret, len = CLNT_PERROR_BUFLEN;
CLNT_GETERR(rpch, &e);
ret = snprintf(str, len, "%s: %s", s, clnt_sperrno(e.re_status));
if (ret < 0)
ret = 0;
else if (ret >= len)
goto truncated;
str += ret;
len -= ret;
switch (e.re_status) {
case RPC_SUCCESS:
case RPC_CANTENCODEARGS:
case RPC_CANTDECODERES:
case RPC_TIMEDOUT:
case RPC_PROGUNAVAIL:
case RPC_PROCUNAVAIL:
case RPC_CANTDECODEARGS:
case RPC_SYSTEMERROR:
case RPC_UNKNOWNHOST:
case RPC_UNKNOWNPROTO:
case RPC_PMAPFAILURE:
case RPC_PROGNOTREGISTERED:
case RPC_FAILED:
break;
case RPC_CANTSEND:
case RPC_CANTRECV:
ret = snprintf(str, len, "; errno = %s", strerror(e.re_errno));
if (ret < 0 || ret >= len)
goto truncated;
break;
case RPC_VERSMISMATCH:
ret = snprintf(str, len,
"; low version = %u, high version = %u",
e.re_vers.low, e.re_vers.high);
if (ret < 0 || ret >= len)
goto truncated;
break;
case RPC_AUTHERROR:
ret = snprintf(str, len, "; why = ");
if (ret < 0)
ret = 0;
else if (ret >= len)
goto truncated;
str += ret;
len -= ret;
err = auth_errmsg(e.re_why);
if (err != NULL) {
ret = snprintf(str, len, "%s", err);
if (ret < 0 || ret >= len)
goto truncated;
} else {
ret = snprintf(str, len,
"(unknown authentication error - %d)",
(int) e.re_why);
if (ret < 0 || ret >= len)
goto truncated;
}
break;
case RPC_PROGVERSMISMATCH:
ret = snprintf(str, len,
"; low version = %u, high version = %u",
e.re_vers.low, e.re_vers.high);
if (ret < 0 || ret >= len)
goto truncated;
break;
default:
ret = snprintf(str, len, "; s1 = %u, s2 = %u",
e.re_lb.s1, e.re_lb.s2);
if (ret < 0 || ret >= len)
goto truncated;
break;
}
if (strlcat(buf, "\n", CLNT_PERROR_BUFLEN) >= CLNT_PERROR_BUFLEN)
goto truncated;
return (buf);
truncated:
snprintf(buf + CLNT_PERROR_BUFLEN - 5, 5, "...\n");
return (buf);
}
DEF_WEAK(clnt_sperror);
void
clnt_perror(CLIENT *rpch, char *s)
{
(void) fprintf(stderr, "%s", clnt_sperror(rpch, s));
}
DEF_WEAK(clnt_perror);
static const char *const rpc_errlist[] = {
"RPC: Success",
"RPC: Can't encode arguments",
"RPC: Can't decode result",
"RPC: Unable to send",
"RPC: Unable to receive",
"RPC: Timed out",
"RPC: Incompatible versions of RPC",
"RPC: Authentication error",
"RPC: Program unavailable",
"RPC: Program/version mismatch",
"RPC: Procedure unavailable",
"RPC: Server can't decode arguments",
"RPC: Remote system error",
"RPC: Unknown host",
"RPC: Port mapper failure",
"RPC: Program not registered",
"RPC: Failed (unspecified error)",
"RPC: Unknown protocol"
};
char *
clnt_sperrno(enum clnt_stat stat)
{
unsigned int errnum = stat;
if (errnum < (sizeof(rpc_errlist)/sizeof(rpc_errlist[0])))
return (char *)rpc_errlist[errnum];
return ("RPC: (unknown error code)");
}
DEF_WEAK(clnt_sperrno);
void
clnt_perrno(enum clnt_stat num)
{
(void) fprintf(stderr, "%s\n", clnt_sperrno(num));
}
char *
clnt_spcreateerror(char *s)
{
switch (rpc_createerr.cf_stat) {
case RPC_PMAPFAILURE:
(void) snprintf(buf, CLNT_PERROR_BUFLEN, "%s: %s - %s\n", s,
clnt_sperrno(rpc_createerr.cf_stat),
clnt_sperrno(rpc_createerr.cf_error.re_status));
break;
case RPC_SYSTEMERROR:
(void) snprintf(buf, CLNT_PERROR_BUFLEN, "%s: %s - %s\n", s,
clnt_sperrno(rpc_createerr.cf_stat),
strerror(rpc_createerr.cf_error.re_errno));
break;
default:
(void) snprintf(buf, CLNT_PERROR_BUFLEN, "%s: %s\n", s,
clnt_sperrno(rpc_createerr.cf_stat));
break;
}
buf[CLNT_PERROR_BUFLEN-2] = '\n';
buf[CLNT_PERROR_BUFLEN-1] = '\0';
return (buf);
}
DEF_WEAK(clnt_spcreateerror);
void
clnt_pcreateerror(char *s)
{
fprintf(stderr, "%s", clnt_spcreateerror(s));
}
DEF_WEAK(clnt_pcreateerror);
static const char *const auth_errlist[] = {
"Authentication OK",
"Invalid client credential",
"Server rejected credential",
"Invalid client verifier",
"Server rejected verifier",
"Client credential too weak",
"Invalid server verifier",
"Failed (unspecified error)"
};
static char *
auth_errmsg(enum auth_stat stat)
{
unsigned int errnum = stat;
if (errnum < (sizeof(auth_errlist)/sizeof(auth_errlist[0])))
return (char *)auth_errlist[errnum];
return (NULL);
}