/* * If a clnt_call gets an RPC error, force the message out here with details. * This would be nice to send to commd_debug(), but we can't call rpc.mdcommd * code from libmeta. */ static void mdmn_handle_RPC_error(CLIENT *clnt, char *ident, md_mn_nodeid_t nid) { /* * This is sized for a max message which would look like this: * "mdmn_wakeup_initiator: rpc.mdcommd node 4294967295" */ char errstr[51]; struct rpc_err e; CLNT_GETERR((CLIENT *) clnt, &e); if (meta_rpc_err_mask() & (1 << e.re_status)) { if (nid == 0) { (void) snprintf(errstr, sizeof (errstr), "%s: %s node (local)", ident, COMMD_PROGNAME); } else { (void) snprintf(errstr, sizeof (errstr), "%s: %s node %d", ident, COMMD_PROGNAME, nid); } syslog(LOG_WARNING, "mdmn_handle_RPC_error: %s", clnt_sperror(clnt, errstr)); } }
/* * Print reply error info */ char * clnt_sperror (CLIENT * rpch, const char *msg) { char chrbuf[1024]; struct rpc_err e; char *err; char *str = _buf (); char *strstart = str; int len; if (str == NULL) return NULL; CLNT_GETERR (rpch, &e); len = sprintf (str, "%s: ", msg); str += len; (void) strcpy(str, clnt_sperrno(e.re_status)); str += strlen(str); switch (e.re_status) { case RPC_SUCCESS: case RPC_CANTENCODEARGS: case RPC_CANTDECODERES: case RPC_TIMEDOUT: case RPC_PROGUNAVAIL: case RPC_PROCUNAVAIL: case RPC_CANTDECODEARGS: case RPC_SYSTEMERROR: case RPC_UNKNOWNHOST: case RPC_UNKNOWNPROTO: case RPC_PMAPFAILURE: case RPC_PROGNOTREGISTERED: case RPC_FAILED: break; case RPC_CANTSEND: case RPC_CANTRECV: strerror_r (e.re_errno, chrbuf, sizeof chrbuf); len = sprintf (str, "; errno = %s", chrbuf); str += len; break; case RPC_VERSMISMATCH: len= sprintf (str, _("; low version = %lu, high version = %lu"), e.re_vers.low, e.re_vers.high); str += len; break; case RPC_AUTHERROR: err = auth_errmsg (e.re_why); (void) strcpy(str, _("; why = ")); str += strlen(str); if (err != NULL) { (void) strcpy(str, err); str += strlen(str); } else { len = sprintf (str, _("(unknown authentication error - %d)"), (int) e.re_why); str += len; } break; case RPC_PROGVERSMISMATCH: len = sprintf (str, _("; low version = %lu, high version = %lu"), e.re_vers.low, e.re_vers.high); str += len; break; default: /* unknown */ len = sprintf (str, "; s1 = %lu, s2 = %lu", e.re_lb.s1, e.re_lb.s2); str += len; break; } *str = '\n'; *++str = '\0'; return (strstart); }
/* * Print reply error info */ char * clnt_sperror( CLIENT *rpch, const char *s) { struct rpc_err e; char *err; char *str = _buf(); char *strstart = str; if (str == 0) return (0); CLNT_GETERR(rpch, &e); (void) sprintf(str, "%s: %s", s, clnt_sperrno(e.re_status)); str += strlen(str); switch (e.re_status) { case RPC_SUCCESS: case RPC_CANTENCODEARGS: case RPC_CANTDECODERES: case RPC_TIMEDOUT: case RPC_PROGUNAVAIL: case RPC_PROCUNAVAIL: case RPC_CANTDECODEARGS: case RPC_SYSTEMERROR: case RPC_UNKNOWNHOST: case RPC_UNKNOWNPROTO: case RPC_PMAPFAILURE: case RPC_PROGNOTREGISTERED: case RPC_FAILED: break; case RPC_CANTSEND: case RPC_CANTRECV: (void) snprintf(str, CLNT_PERROR_BUFLEN - (str - strstart), "; errno = %s\n", strerror(e.re_errno)); break; case RPC_VERSMISMATCH: (void) sprintf(str, "; low version = %lu, high version = %lu\n", (u_long)e.re_vers.low, (u_long)e.re_vers.high); break; case RPC_AUTHERROR: err = auth_errmsg(e.re_why); (void) sprintf(str,"; why = "); str += strlen(str); if (err != NULL) { (void) sprintf(str, "%s\n",err); } else { (void) sprintf(str, "(unknown authentication error - %d)\n", (int) e.re_why); } break; case RPC_PROGVERSMISMATCH: (void) sprintf(str, "; low version = %lu, high version = %lu\n", (u_long)e.re_vers.low, (u_long)e.re_vers.high); break; default: /* unknown */ (void) sprintf(str, "; s1 = %lu, s2 = %lu\n", (long)e.re_lb.s1, (long)e.re_lb.s2); break; } strstart[CLNT_PERROR_BUFLEN-2] = '\n'; strstart[CLNT_PERROR_BUFLEN-1] = '\0'; return(strstart) ; }
/* * Return string reply error info. For use after clnt_call(). * It allocates the buffer of size MAXPATHLEN and assumes * caller's responsibility to free the memory after use. */ char * clnt_sperror(const CLIENT *cl, const char *s) { struct rpc_err e; #ifdef notyet char *err; #endif char *str; char *strstart; str = kmem_alloc(MAXPATHLEN, KM_SLEEP); strstart = str; CLNT_GETERR((CLIENT *) cl, &e); (void) sprintf(str, "%s: ", s); str += strlen(str); (void) strcpy(str, clnt_sperrno(e.re_status)); str += strlen(str); switch (e.re_status) { case RPC_SUCCESS: case RPC_CANTENCODEARGS: case RPC_CANTDECODERES: case RPC_TIMEDOUT: case RPC_PROGUNAVAIL: case RPC_PROCUNAVAIL: case RPC_CANTDECODEARGS: case RPC_SYSTEMERROR: case RPC_UNKNOWNHOST: case RPC_UNKNOWNPROTO: case RPC_UNKNOWNADDR: case RPC_NOBROADCAST: case RPC_RPCBFAILURE: case RPC_PROGNOTREGISTERED: case RPC_FAILED: case RPC_INPROGRESS: break; #ifdef notyet case RPC_N2AXLATEFAILURE: (void) sprintf(str, "; %s", netdir_sperror()); break; #endif case RPC_TLIERROR: #ifdef notyet (void) sprintf(str, "; %s", t_errlist[e.re_terrno]); #else (void) sprintf(str, "; %d", e.re_terrno); #endif str += strlen(str); if (e.re_errno) { #ifdef notyet (void) sprintf(str, "; %s", strerror(e.re_errno)); #else (void) sprintf(str, "; %d", e.re_errno); #endif } break; case RPC_CANTSEND: case RPC_CANTRECV: if (e.re_errno) { #ifdef notyet (void) sprintf(str, "; errno = %s", strerror(e.re_errno)); #else (void) sprintf(str, "; errno = %d", e.re_errno); #endif str += strlen(str); } if (e.re_terrno) { #ifdef notyet (void) sprintf(str, "; %s", t_errlist[e.re_terrno]); #else (void) sprintf(str, "; %d", e.re_terrno); #endif } break; case RPC_VERSMISMATCH: (void) sprintf(str, "; low version = %" PRIu32 ", high version = %" PRIu32, e.re_vers.low, e.re_vers.high); break; #ifdef notyet case RPC_AUTHERROR: err = auth_errmsg(e.re_why); (void) sprintf(str, "; why = "); str += strlen(str); if (err != NULL) { (void) sprintf(str, "%s", err); } else { (void) sprintf(str, "(unknown authentication error - %d)", (int)e.re_why); } break; #endif case RPC_PROGVERSMISMATCH: (void) sprintf(str, "; low version = %" PRIu32 ", high version = %" PRIu32, e.re_vers.low, e.re_vers.high); break; default: /* unknown */ (void) sprintf(str, "; s1 = %" PRIu32 ", s2 = %" PRIu32, e.re_lb.s1, e.re_lb.s2); break; } return (strstart); }
static enum clnt_stat clnt_reconnect_call( CLIENT *cl, /* client handle */ struct rpc_callextra *ext, /* call metadata */ rpcproc_t proc, /* procedure number */ struct mbuf *args, /* pointer to args */ struct mbuf **resultsp, /* pointer to results */ struct timeval utimeout) { struct rc_data *rc = (struct rc_data *)cl->cl_private; CLIENT *client; enum clnt_stat stat; int tries, error; tries = 0; do { mtx_lock(&rc->rc_lock); if (rc->rc_closed) { mtx_unlock(&rc->rc_lock); return (RPC_CANTSEND); } if (!rc->rc_client) { mtx_unlock(&rc->rc_lock); stat = clnt_reconnect_connect(cl); if (stat == RPC_SYSTEMERROR) { error = tsleep(&fake_wchan, rc->rc_intr ? PCATCH | PBDRY : 0, "rpccon", hz); if (error == EINTR || error == ERESTART) return (RPC_INTR); tries++; if (tries >= rc->rc_retries) return (stat); continue; } if (stat != RPC_SUCCESS) return (stat); mtx_lock(&rc->rc_lock); } if (!rc->rc_client) { mtx_unlock(&rc->rc_lock); stat = RPC_FAILED; continue; } CLNT_ACQUIRE(rc->rc_client); client = rc->rc_client; mtx_unlock(&rc->rc_lock); stat = CLNT_CALL_MBUF(client, ext, proc, args, resultsp, utimeout); if (stat != RPC_SUCCESS) { if (!ext) CLNT_GETERR(client, &rc->rc_err); } if (stat == RPC_TIMEDOUT) { /* * Check for async send misfeature for NLM * protocol. */ if ((rc->rc_timeout.tv_sec == 0 && rc->rc_timeout.tv_usec == 0) || (rc->rc_timeout.tv_sec == -1 && utimeout.tv_sec == 0 && utimeout.tv_usec == 0)) { CLNT_RELEASE(client); break; } } if (stat == RPC_TIMEDOUT || stat == RPC_CANTSEND || stat == RPC_CANTRECV) { tries++; if (tries >= rc->rc_retries) { CLNT_RELEASE(client); break; } if (ext && ext->rc_feedback) ext->rc_feedback(FEEDBACK_RECONNECT, proc, ext->rc_feedback_arg); mtx_lock(&rc->rc_lock); /* * Make sure that someone else hasn't already * reconnected by checking if rc_client has changed. * If not, we are done with the client and must * do CLNT_RELEASE(client) twice to dispose of it, * because there is both an initial refcnt and one * acquired by CLNT_ACQUIRE() above. */ if (rc->rc_client == client) { rc->rc_client = NULL; mtx_unlock(&rc->rc_lock); CLNT_RELEASE(client); } else { mtx_unlock(&rc->rc_lock); } CLNT_RELEASE(client); } else { CLNT_RELEASE(client); break; } } while (stat != RPC_SUCCESS); KASSERT(stat != RPC_SUCCESS || *resultsp, ("RPC_SUCCESS without reply")); return (stat); }
/* * Print reply error info */ char * clnt_sperror(CLIENT *rpch, const char *s) { struct rpc_err e; char *err; char *str; char *strstart; size_t len, i; if (rpch == NULL || s == NULL) return (0); str = _buf(); /* side effect: sets CLNT_PERROR_BUFLEN */ if (str == 0) return (0); len = CLNT_PERROR_BUFLEN; strstart = str; CLNT_GETERR(rpch, &e); if (snprintf(str, len, "%s: ", s) > 0) { i = strlen(str); str += i; len -= i; } (void)strncpy(str, clnt_sperrno(e.re_status), len - 1); i = strlen(str); str += i; len -= i; 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: snprintf(str, len, "; errno = %s", strerror(e.re_errno)); i = strlen(str); if (i > 0) { str += i; len -= i; } break; case RPC_VERSMISMATCH: snprintf(str, len, "; low version = %u, high version = %u", e.re_vers.low, e.re_vers.high); i = strlen(str); if (i > 0) { str += i; len -= i; } break; case RPC_AUTHERROR: err = auth_errmsg(e.re_why); snprintf(str, len, "; why = "); i = strlen(str); if (i > 0) { str += i; len -= i; } if (err != NULL) { snprintf(str, len, "%s", err); } else { snprintf(str, len, "(unknown authentication error - %d)", (int)e.re_why); } i = strlen(str); if (i > 0) { str += i; len -= i; } break; case RPC_PROGVERSMISMATCH: snprintf(str, len, "; low version = %u, high version = %u", e.re_vers.low, e.re_vers.high); i = strlen(str); if (i > 0) { str += i; len -= i; } break; default: /* unknown */ snprintf(str, len, "; s1 = %u, s2 = %u", e.re_lb.s1, e.re_lb.s2); i = strlen(str); if (i > 0) { str += i; len -= i; } break; } strstart[CLNT_PERROR_BUFLEN - 1] = '\0'; return (strstart); }
/* * Print reply error info */ char * clnt_sperror(CLIENT *rpch, char *s) { struct rpc_err e; void clnt_perrno(); char *err; char *bufstart = get_buf(); char *str = bufstart; char *strstart = str; char *strend; if (str == 0) return (0); strend = str + BUFSIZ; CLNT_GETERR(rpch, &e); strncpy (str, s, BUFSIZ - 1); str[BUFSIZ - 1] = 0; strncat (str, ": ", BUFSIZ - 1 - strlen (bufstart)); str += strlen(str); strncat (str, clnt_sperrno(e.re_status), BUFSIZ - 1 - strlen (bufstart)); strstart[BUFSIZ - 1] = '\0'; str += strlen(str); switch (e.re_status) { case RPC_SUCCESS: case RPC_CANTENCODEARGS: case RPC_CANTDECODERES: case RPC_TIMEDOUT: case RPC_PROGUNAVAIL: case RPC_PROCUNAVAIL: case RPC_CANTDECODEARGS: case RPC_SYSTEMERROR: case RPC_UNKNOWNHOST: case RPC_UNKNOWNPROTO: case RPC_PMAPFAILURE: case RPC_PROGNOTREGISTERED: case RPC_FAILED: break; case RPC_CANTSEND: case RPC_CANTRECV: /* 10 for the string */ if (str - bufstart + 10 + strlen(strerror(e.re_errno)) < BUFSIZ) (void) snprintf(str, strend-str, "; errno = %s", strerror(e.re_errno)); str += strlen(str); break; case RPC_VERSMISMATCH: /* 33 for the string, 22 for the numbers */ if(str - bufstart + 33 + 22 < BUFSIZ) (void) snprintf(str, strend-str, "; low version = %lu, high version = %lu", (u_long) e.re_vers.low, (u_long) e.re_vers.high); str += strlen(str); break; case RPC_AUTHERROR: err = auth_errmsg(e.re_why); /* 8 for the string */ if(str - bufstart + 8 < BUFSIZ) (void) snprintf(str, strend-str, "; why = "); str += strlen(str); if (err != NULL) { if(str - bufstart + strlen(err) < BUFSIZ) (void) snprintf(str, strend-str, "%s",err); } else { /* 33 for the string, 11 for the number */ if(str - bufstart + 33 + 11 < BUFSIZ) (void) snprintf(str, strend-str, "(unknown authentication error - %d)", (int) e.re_why); } str += strlen(str); break; case RPC_PROGVERSMISMATCH: /* 33 for the string, 22 for the numbers */ if(str - bufstart + 33 + 22 < BUFSIZ) (void) snprintf(str, strend-str, "; low version = %lu, high version = %lu", (u_long) e.re_vers.low, (u_long) e.re_vers.high); str += strlen(str); break; default: /* unknown */ /* 14 for the string, 22 for the numbers */ if(str - bufstart + 14 + 22 < BUFSIZ) (void) snprintf(str, strend-str, "; s1 = %lu, s2 = %lu", (u_long) e.re_lb.s1, (u_long) e.re_lb.s2); str += strlen(str); break; } if (str - bufstart + 1 < BUFSIZ) (void) snprintf(str, strend-str, "\n"); return(strstart) ; }
/* * Print reply error info */ 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 == -1) 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 == -1 || 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 == -1 || ret >= len) goto truncated; break; case RPC_AUTHERROR: ret = snprintf(str, len, "; why = "); if (ret == -1) 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 == -1 || ret >= len) goto truncated; } else { ret = snprintf(str, len, "(unknown authentication error - %d)", (int) e.re_why); if (ret == -1 || 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 == -1 || ret >= len) goto truncated; break; default: /* unknown */ ret = snprintf(str, len, "; s1 = %u, s2 = %u", e.re_lb.s1, e.re_lb.s2); if (ret == -1 || 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); }