From ccaf72887e87866a51356d16a08c713bc9273c92 Mon Sep 17 00:00:00 2001 From: Apple Date: Thu, 8 Jul 2004 21:24:02 +0000 Subject: [PATCH] network_cmds-176.3.3.tar.gz --- rpc_lockd.tproj/kern.c | 2 + rpc_lockd.tproj/lock_proc.c | 297 +++++++++++++++++++++++++++-------- rpc_lockd.tproj/lockd.c | 86 +++++++--- rpc_lockd.tproj/lockd_lock.c | 247 ++++++++++++++++++++--------- rpc_lockd.tproj/lockd_lock.h | 9 +- rpc_statd.tproj/procs.c | 32 +++- 6 files changed, 507 insertions(+), 166 deletions(-) diff --git a/rpc_lockd.tproj/kern.c b/rpc_lockd.tproj/kern.c index a231b87..eb29905 100644 --- a/rpc_lockd.tproj/kern.c +++ b/rpc_lockd.tproj/kern.c @@ -357,6 +357,8 @@ lock_request(LOCKD_MSG *msg) msg->lm_fl.l_type == F_WRLCK ? "write" : "read", from_addr((struct sockaddr *)&msg->lm_addr)); + monitor_lock_host_by_addr((struct sockaddr *)&msg->lm_addr); + if (msg->lm_flags & LOCKD_MSG_NFSV3) { arg4.cookie.n_bytes = (char *)&msg->lm_xid; arg4.cookie.n_len = sizeof(msg->lm_xid); diff --git a/rpc_lockd.tproj/lock_proc.c b/rpc_lockd.tproj/lock_proc.c index 2029deb..1ae97ef 100644 --- a/rpc_lockd.tproj/lock_proc.c +++ b/rpc_lockd.tproj/lock_proc.c @@ -48,6 +48,8 @@ __RCSID("$NetBSD: lock_proc.c,v 1.7 2000/10/11 20:23:56 is Exp $"); #include #include #include +#include +#include #include #include @@ -62,7 +64,6 @@ __RCSID("$NetBSD: lock_proc.c,v 1.7 2000/10/11 20:23:56 is Exp $"); static void log_from_addr(const char *, struct svc_req *); static void log_netobj(netobj *obj); -static int addrcmp(struct sockaddr *, struct sockaddr *); /* log_from_addr ----------------------------------------------------------- */ /* @@ -156,10 +157,27 @@ static struct sockaddr_storage clnt_cache_addr[CLIENT_CACHE_SIZE]; static rpcvers_t clnt_cache_vers[CLIENT_CACHE_SIZE]; static int clnt_cache_next_to_use = 0; -static int -addrcmp(sa1, sa2) - struct sockaddr *sa1; - struct sockaddr *sa2; +/* + * Because lockd is single-threaded, slow/unresponsive portmappers on + * clients can cause serious performance issues. So, we keep a list of + * these bad hosts, and limit how often we try to get_client() for those hosts. + */ +struct badhost { + TAILQ_ENTRY(badhost) list; + struct sockaddr_storage addr; /* host address */ + int count; /* # of occurences */ + time_t timelast; /* last attempted */ + time_t timenext; /* next allowed */ +}; +TAILQ_HEAD(badhostlist_head, badhost); +static struct badhostlist_head badhostlist_head = TAILQ_HEAD_INITIALIZER(badhostlist_head); +#define BADHOST_CLIENT_TOOK_TOO_LONG 5 /* In seconds */ +#define BADHOST_INITIAL_DELAY 120 /* In seconds */ +#define BADHOST_MAXIMUM_DELAY 3600 /* In seconds */ +#define BADHOST_DELAY_INCREMENT 300 /* In seconds */ + +int +addrcmp(const struct sockaddr *sa1, const struct sockaddr *sa2) { int len; void *p1, *p2; @@ -190,82 +208,190 @@ get_client(host_addr, vers) struct sockaddr *host_addr; rpcvers_t vers; { - CLIENT *client; + CLIENT *client, *cached_client; struct timeval retry_time, time_now; int i; int sock_no; + time_t time_start, cache_time = 0; + struct badhost *badhost, *nextbadhost; gettimeofday(&time_now, NULL); /* - * Search for the given client in the cache, zapping any expired - * entries that we happen to notice in passing. + * Search for the given client in the cache. */ + cached_client = NULL; for (i = 0; i < CLIENT_CACHE_SIZE; i++) { client = clnt_cache_ptr[i]; - if (client && ((clnt_cache_time[i] + CLIENT_CACHE_LIFETIME) - < time_now.tv_sec)) { - /* Cache entry has expired. */ - if (debug_level > 3) - syslog(LOG_DEBUG, "Expired CLIENT* in cache"); - clnt_cache_time[i] = 0L; - clnt_destroy(client); - clnt_cache_ptr[i] = NULL; - client = NULL; - } - if (client && !addrcmp((struct sockaddr *)&clnt_cache_addr[i], - host_addr) && clnt_cache_vers[i] == vers) { - /* Found it! */ + if (!client) + continue; + if (clnt_cache_vers[i] != vers) + continue; + if (addrcmp((struct sockaddr *)&clnt_cache_addr[i], host_addr)) + continue; + /* Found it! */ + if (((clnt_cache_time[i] + CLIENT_CACHE_LIFETIME) > time_now.tv_sec)) { if (debug_level > 3) syslog(LOG_DEBUG, "Found CLIENT* in cache"); return (client); } + syslog(LOG_DEBUG, "Found expired CLIENT* in cache"); + cached_client = client; + /* if we end up reusing this guy, make sure we keep the same timestamp */ + cache_time = clnt_cache_time[i]; + clnt_cache_time[i] = 0L; + clnt_cache_ptr[i] = NULL; + client = NULL; + break; } - if (debug_level > 3) - syslog(LOG_DEBUG, "CLIENT* not found in cache, creating"); + /* + * Search for the given client in the badhost list. + */ + badhost = TAILQ_FIRST(&badhostlist_head); + while (badhost) { + nextbadhost = TAILQ_NEXT(badhost, list); + if (!addrcmp(host_addr, (struct sockaddr *)&badhost->addr)) + break; + if ((badhost->timelast + BADHOST_MAXIMUM_DELAY) < time_now.tv_sec) { + /* cleanup entries we haven't heard from in a while */ + TAILQ_REMOVE(&badhostlist_head, badhost, list); + free(badhost); + } + badhost = nextbadhost; + } - /* Not found in cache. Free the next entry if it is in use. */ + if (badhost && (time_now.tv_sec < badhost->timenext)) { + /* + * We've got a badhost, and we don't want to try + * consulting it again yet. If we've got a stale + * cached CLIENT*, go ahead and try to use that. + */ + if (cached_client) { + syslog(LOG_DEBUG, "badhost delayed: stale CLIENT* found in cache"); + /* Free the next entry if it is in use. */ + if (clnt_cache_ptr[clnt_cache_next_to_use]) { + clnt_destroy(clnt_cache_ptr[clnt_cache_next_to_use]); + clnt_cache_ptr[clnt_cache_next_to_use] = NULL; + } + client = cached_client; + goto update_cache_entry; + } + syslog(LOG_DEBUG, "badhost delayed: valid CLIENT* not found in cache"); + return NULL; + } + + if (debug_level > 3) { + if (!cached_client) + syslog(LOG_DEBUG, "CLIENT* not found in cache, creating"); + else + syslog(LOG_DEBUG, "stale CLIENT* found in cache, updating"); + } + + /* Free the next entry if it is in use. */ if (clnt_cache_ptr[clnt_cache_next_to_use]) { clnt_destroy(clnt_cache_ptr[clnt_cache_next_to_use]); clnt_cache_ptr[clnt_cache_next_to_use] = NULL; } /* Create the new client handle */ + time_start = time_now.tv_sec; sock_no = RPC_ANYSOCK; retry_time.tv_sec = 5; retry_time.tv_usec = 0; ((struct sockaddr_in *)host_addr)->sin_port = 0; /* Force consultation with portmapper */ client = clntudp_create((struct sockaddr_in *)host_addr, NLM_PROG, vers, retry_time, &sock_no); + + gettimeofday(&time_now, NULL); + if (time_now.tv_sec - time_start >= BADHOST_CLIENT_TOOK_TOO_LONG) { + /* + * The client create took a long time! (slow/unresponsive portmapper?) + * Add/update an entry in the badhost list. + */ + if (!badhost && (badhost = malloc(sizeof(struct badhost)))) { + /* allocate new badhost */ + memcpy(&badhost->addr, host_addr, host_addr->sa_len); + badhost->count = 0; + TAILQ_INSERT_TAIL(&badhostlist_head, badhost, list); + } + if (badhost) { + /* update count and times */ + badhost->count++; + badhost->timelast = time_now.tv_sec; + if (badhost->count == 1) { + /* first timers get a shorter initial delay */ + badhost->timenext = time_now.tv_sec + BADHOST_INITIAL_DELAY; + } else { + /* multiple offenders get an increasingly larger delay */ + int delay = (badhost->count - 1) * BADHOST_DELAY_INCREMENT; + if (delay > BADHOST_MAXIMUM_DELAY) + delay = BADHOST_MAXIMUM_DELAY; + badhost->timenext = time_now.tv_sec + delay; + } + /* move to end of list */ + TAILQ_REMOVE(&badhostlist_head, badhost, list); + TAILQ_INSERT_TAIL(&badhostlist_head, badhost, list); + } + } else if (badhost) { + /* host seems good now, remove it from list */ + TAILQ_REMOVE(&badhostlist_head, badhost, list); + free(badhost); + badhost = NULL; + } + if (!client) { - syslog(LOG_DEBUG, "%s", clnt_spcreateerror("clntudp_create")); - syslog(LOG_DEBUG, "Unable to contact %s", - inet_ntoa(((struct sockaddr_in *)host_addr)->sin_addr)); - return NULL; + /* We couldn't get a new CLIENT* */ + if (!cached_client) { + syslog(LOG_WARNING, "Unable to contact %s: %s", + inet_ntoa(((struct sockaddr_in *)host_addr)->sin_addr), + clnt_spcreateerror("clntudp_create")); + return NULL; + } + /* + * We couldn't get updated info from portmapper, but we did + * still have the stale cached data. So we might as well try + * to use it. + */ + client = cached_client; + syslog(LOG_WARNING, "Unable to update contact info for %s: %s", + inet_ntoa(((struct sockaddr_in *)host_addr)->sin_addr), + clnt_spcreateerror("clntudp_create")); + } else { + /* + * We've got a new/updated CLIENT* for this host. + * So, destroy any previously cached CLIENT*. + */ + if (cached_client) + clnt_destroy(cached_client); + + /* + * Disable the default timeout, so we can specify our own in calls + * to clnt_call(). (Note that the timeout is a different concept + * from the retry period set in clnt_udp_create() above.) + */ + retry_time.tv_sec = -1; + retry_time.tv_usec = -1; + clnt_control(client, CLSET_TIMEOUT, (char *)&retry_time); + + if (debug_level > 3) + syslog(LOG_DEBUG, "Created CLIENT* for %s", + inet_ntoa(((struct sockaddr_in *)host_addr)->sin_addr)); + + /* make sure the new entry gets the current timestamp */ + cache_time = time_now.tv_sec; } - /* Success - update the cache entry */ +update_cache_entry: + /* Success (of some sort) - update the cache entry */ clnt_cache_ptr[clnt_cache_next_to_use] = client; memcpy(&clnt_cache_addr[clnt_cache_next_to_use], host_addr, host_addr->sa_len); clnt_cache_vers[clnt_cache_next_to_use] = vers; - clnt_cache_time[clnt_cache_next_to_use] = time_now.tv_sec; - if (++clnt_cache_next_to_use > CLIENT_CACHE_SIZE) + clnt_cache_time[clnt_cache_next_to_use] = cache_time; + if (++clnt_cache_next_to_use >= CLIENT_CACHE_SIZE) clnt_cache_next_to_use = 0; - /* - * Disable the default timeout, so we can specify our own in calls - * to clnt_call(). (Note that the timeout is a different concept - * from the retry period set in clnt_udp_create() above.) - */ - retry_time.tv_sec = -1; - retry_time.tv_usec = -1; - clnt_control(client, CLSET_TIMEOUT, (char *)&retry_time); - - if (debug_level > 3) - syslog(LOG_DEBUG, "Created CLIENT* for %s", - inet_ntoa(((struct sockaddr_in *)host_addr)->sin_addr)); return client; } @@ -273,12 +399,12 @@ get_client(host_addr, vers) /* transmit_result --------------------------------------------------------- */ /* * Purpose: Transmit result for nlm_xxx_msg pseudo-RPCs - * Returns: Nothing - we have no idea if the datagram got there + * Returns: success (0) or failure (-1) at sending the datagram * Notes: clnt_call() will always fail (with timeout) as we are * calling it with timeout 0 as a hack to just issue a datagram * without expecting a result */ -void +int transmit_result(opcode, result, addr) int opcode; nlm_res *result; @@ -299,17 +425,19 @@ transmit_result(opcode, result, addr) if (debug_level > 2) syslog(LOG_DEBUG, "clnt_call returns %d(%s)", success, clnt_sperrno(success)); + return (0); } + return (-1); } /* transmit4_result --------------------------------------------------------- */ /* * Purpose: Transmit result for nlm4_xxx_msg pseudo-RPCs - * Returns: Nothing - we have no idea if the datagram got there + * Returns: success (0) or failure (-1) at sending the datagram * Notes: clnt_call() will always fail (with timeout) as we are * calling it with timeout 0 as a hack to just issue a datagram * without expecting a result */ -void +int transmit4_result(opcode, result, addr) int opcode; nlm4_res *result; @@ -330,7 +458,9 @@ transmit4_result(opcode, result, addr) if (debug_level > 2) syslog(LOG_DEBUG, "clnt_call returns %d(%s)", success, clnt_sperrno(success)); + return (0); } + return (-1); } /* @@ -342,7 +472,10 @@ nlmtonlm4(arg, arg4) struct nlm_lock *arg; struct nlm4_lock *arg4; { - memcpy(arg4, arg, sizeof(nlm_lock)); + arg4->caller_name = arg->caller_name; + arg4->fh = arg->fh; + arg4->oh = arg->oh; + arg4->svid = arg->svid; arg4->l_offset = arg->l_offset; arg4->l_len = arg->l_len; } @@ -513,8 +646,20 @@ nlm_lock_msg_1_svc(arg, rqstp) res.cookie = arg->cookie; res.stat.stat = getlock(&arg4, rqstp, LOCK_ASYNC | LOCK_MON); - transmit_result(NLM_LOCK_RES, &res, - (struct sockaddr *)svc_getcaller(rqstp->rq_xprt)); + if (transmit_result(NLM_LOCK_RES, &res, + (struct sockaddr *)svc_getcaller(rqstp->rq_xprt)) < 0) { + /* if res.stat.stat was success/blocked, then unlock/cancel */ + if (res.stat.stat == nlm_granted) + unlock(&arg4.alock, LOCK_V4); + else if (res.stat.stat == nlm_blocked) { + nlm4_cancargs carg; + carg.cookie = arg4.cookie; + carg.block = arg4.block; + carg.exclusive = arg4.exclusive; + carg.alock = arg4.alock; + cancellock(&carg, 0); + } + } return (NULL); } @@ -566,8 +711,10 @@ nlm_cancel_msg_1_svc(arg, rqstp) res.cookie = arg->cookie; res.stat.stat = cancellock(&arg4, 0); - transmit_result(NLM_CANCEL_RES, &res, - (struct sockaddr *)svc_getcaller(rqstp->rq_xprt)); + if (transmit_result(NLM_CANCEL_RES, &res, + (struct sockaddr *)svc_getcaller(rqstp->rq_xprt)) < 0) { + /* XXX do we need to (un)do anything if this fails? */ + } return (NULL); } @@ -614,8 +761,10 @@ nlm_unlock_msg_1_svc(arg, rqstp) res.stat.stat = unlock(&arg4, 0); res.cookie = arg->cookie; - transmit_result(NLM_UNLOCK_RES, &res, - (struct sockaddr *)svc_getcaller(rqstp->rq_xprt)); + if (transmit_result(NLM_UNLOCK_RES, &res, + (struct sockaddr *)svc_getcaller(rqstp->rq_xprt)) < 0) { + /* XXX do we need to (un)do anything if this fails? */ + } return (NULL); } @@ -697,8 +846,10 @@ nlm_granted_msg_1_svc(arg, rqstp) res.cookie = arg->cookie; - transmit_result(NLM_GRANTED_RES, &res, - (struct sockaddr *)svc_getcaller(rqstp->rq_xprt)); + if (transmit_result(NLM_GRANTED_RES, &res, + (struct sockaddr *)svc_getcaller(rqstp->rq_xprt)) < 0) { + /* XXX do we need to (un)do anything if this fails? */ + } return (NULL); } @@ -1078,8 +1229,20 @@ nlm4_lock_msg_4_svc(arg, rqstp) res.cookie = arg->cookie; res.stat.stat = getlock(arg, rqstp, LOCK_MON | LOCK_ASYNC | LOCK_V4); - transmit4_result(NLM4_LOCK_RES, &res, - (struct sockaddr *)svc_getcaller(rqstp->rq_xprt)); + if (transmit4_result(NLM4_LOCK_RES, &res, + (struct sockaddr *)svc_getcaller(rqstp->rq_xprt)) < 0) { + /* if res.stat.stat was success/blocked, then unlock/cancel */ + if (res.stat.stat == nlm4_granted) + unlock(&arg->alock, LOCK_V4); + else if (res.stat.stat == nlm4_blocked) { + nlm4_cancargs carg; + carg.cookie = arg->cookie; + carg.block = arg->block; + carg.exclusive = arg->exclusive; + carg.alock = arg->alock; + cancellock(&carg, LOCK_V4); + } + } return (NULL); } @@ -1119,8 +1282,10 @@ nlm4_cancel_msg_4_svc(arg, rqstp) res.cookie = arg->cookie; res.stat.stat = cancellock(arg, LOCK_V4); - transmit4_result(NLM4_CANCEL_RES, &res, - (struct sockaddr *)svc_getcaller(rqstp->rq_xprt)); + if (transmit4_result(NLM4_CANCEL_RES, &res, + (struct sockaddr *)svc_getcaller(rqstp->rq_xprt)) < 0) { + /* XXX do we need to (un)do anything if this fails? */ + } return (NULL); } @@ -1161,8 +1326,10 @@ nlm4_unlock_msg_4_svc(arg, rqstp) res.stat.stat = unlock(&arg->alock, LOCK_V4); res.cookie = arg->cookie; - transmit4_result(NLM4_UNLOCK_RES, &res, - (struct sockaddr *)svc_getcaller(rqstp->rq_xprt)); + if (transmit4_result(NLM4_UNLOCK_RES, &res, + (struct sockaddr *)svc_getcaller(rqstp->rq_xprt)) < 0) { + /* XXX do we need to (un)do anything if this fails? */ + } return (NULL); } @@ -1232,8 +1399,10 @@ nlm4_granted_msg_4_svc(arg, rqstp) res.cookie = arg->cookie; - transmit4_result(NLM4_GRANTED_RES, &res, - (struct sockaddr *)svc_getcaller(rqstp->rq_xprt)); + if (transmit4_result(NLM4_GRANTED_RES, &res, + (struct sockaddr *)svc_getcaller(rqstp->rq_xprt)) < 0) { + /* XXX do we need to (un)do anything if this fails? */ + } return (NULL); } diff --git a/rpc_lockd.tproj/lockd.c b/rpc_lockd.tproj/lockd.c index f2d9ef2..7bb5833 100644 --- a/rpc_lockd.tproj/lockd.c +++ b/rpc_lockd.tproj/lockd.c @@ -59,6 +59,7 @@ __RCSID("$NetBSD: lockd.c,v 1.7 2000/08/12 18:08:44 thorpej Exp $"); #include #include #include +#include #include #include @@ -103,6 +104,7 @@ main(argc, argv) int ch; struct sigaction sigalarm; int grace_period = 30; + struct rlimit rlp; while ((ch = getopt(argc, argv, "d:g:wx:")) != (-1)) { switch (ch) { @@ -141,7 +143,7 @@ main(argc, argv) * Note that it is NOT sensible to run this program from inetd - the * protocol assumes that it will run immediately at boot time. */ - if (debug_level != 99 && daemon(0, 0)) { + if (debug_level != 99 && daemon(0, debug_level > 0)) { err(1, "cannot fork"); /* NOTREACHED */ } @@ -152,8 +154,12 @@ main(argc, argv) signal(SIGHUP, handle_sig_cleanup); signal(SIGQUIT, handle_sig_cleanup); - if (claim_pid_file("/var/run/lockd.pid", 0) < 0) - errx(1, "cannot claim pid file"); + openlog("rpc.lockd", debug_level == 99 ? LOG_PERROR : 0, LOG_DAEMON); + + if (claim_pid_file("/var/run/lockd.pid", 0) < 0) { + syslog(LOG_ERR, "cannot claim pid file"); + exit(1); + } if (waitkern) { struct timespec ts; @@ -168,7 +174,6 @@ main(argc, argv) nanosleep(&ts, NULL); } - openlog("rpc.lockd", debug_level == 99 ? LOG_PERROR : 0, LOG_DAEMON); if (debug_level) syslog(LOG_INFO, "Starting, debug level %d", debug_level); else @@ -180,24 +185,48 @@ main(argc, argv) (void)pmap_unset(NLM_PROG, NLM_VERS4); transp = svcudp_create(RPC_ANYSOCK); - if (transp == NULL) - errx(1, "cannot create udp service"); - if (!svc_register(transp, NLM_PROG, NLM_VERS, nlm_prog_1, IPPROTO_UDP)) - errx(1, "unable to register (NLM_PROG, NLM_VERS, udp)"); - if (!svc_register(transp, NLM_PROG, NLM_VERSX, nlm_prog_3, IPPROTO_UDP)) - errx(1, "unable to register (NLM_PROG, NLM_VERSX, udp)"); - if (!svc_register(transp, NLM_PROG, NLM_VERS4, nlm_prog_4, IPPROTO_UDP)) - errx(1, "unable to register (NLM_PROG, NLM_VERS4, udp)"); + if (transp == NULL) { + syslog(LOG_ERR, "cannot create udp service"); + exit(1); + } + if (!svc_register(transp, NLM_PROG, NLM_SM, nlm_prog_0, IPPROTO_UDP)) { + syslog(LOG_ERR, "unable to register (NLM_PROG, NLM_SM, udp)"); + exit(1); + } + if (!svc_register(transp, NLM_PROG, NLM_VERS, nlm_prog_1, IPPROTO_UDP)) { + syslog(LOG_ERR, "unable to register (NLM_PROG, NLM_VERS, udp)"); + exit(1); + } + if (!svc_register(transp, NLM_PROG, NLM_VERSX, nlm_prog_3, IPPROTO_UDP)) { + syslog(LOG_ERR, "unable to register (NLM_PROG, NLM_VERSX, udp)"); + exit(1); + } + if (!svc_register(transp, NLM_PROG, NLM_VERS4, nlm_prog_4, IPPROTO_UDP)) { + syslog(LOG_ERR, "unable to register (NLM_PROG, NLM_VERS4, udp)"); + exit(1); + } transp = svctcp_create(RPC_ANYSOCK, 0, 0); - if (transp == NULL) - errx(1, "cannot create tcp service"); - if (!svc_register(transp, NLM_PROG, NLM_VERS, nlm_prog_1, IPPROTO_TCP)) - errx(1, "unable to register (NLM_PROG, NLM_VERS, tcp)"); - if (!svc_register(transp, NLM_PROG, NLM_VERSX, nlm_prog_3, IPPROTO_TCP)) - errx(1, "unable to register (NLM_PROG, NLM_VERSX, tcp)"); - if (!svc_register(transp, NLM_PROG, NLM_VERS4, nlm_prog_4, IPPROTO_TCP)) - errx(1, "unable to register (NLM_PROG, NLM_VERS4, tcp)"); + if (transp == NULL) { + syslog(LOG_ERR, "cannot create tcp service"); + exit(1); + } + if (!svc_register(transp, NLM_PROG, NLM_SM, nlm_prog_0, IPPROTO_TCP)) { + syslog(LOG_ERR, "unable to register (NLM_PROG, NLM_SM, tcp)"); + exit(1); + } + if (!svc_register(transp, NLM_PROG, NLM_VERS, nlm_prog_1, IPPROTO_TCP)) { + syslog(LOG_ERR, "unable to register (NLM_PROG, NLM_VERS, tcp)"); + exit(1); + } + if (!svc_register(transp, NLM_PROG, NLM_VERSX, nlm_prog_3, IPPROTO_TCP)) { + syslog(LOG_ERR, "unable to register (NLM_PROG, NLM_VERSX, tcp)"); + exit(1); + } + if (!svc_register(transp, NLM_PROG, NLM_VERS4, nlm_prog_4, IPPROTO_TCP)) { + syslog(LOG_ERR, "unable to register (NLM_PROG, NLM_VERS4, tcp)"); + exit(1); + } sigalarm.sa_handler = (sig_t) sigalarm_handler; sigemptyset(&sigalarm.sa_mask); @@ -215,6 +244,18 @@ main(argc, argv) client_pid = client_request(); + /* raise our resource limits as far as they can go */ + if (getrlimit(RLIMIT_NOFILE, &rlp)) { + syslog(LOG_WARNING, "getrlimit(RLIMIT_NOFILE) failed: %s", + strerror(errno)); + } else { + rlp.rlim_cur = rlp.rlim_max; + if (setrlimit(RLIMIT_NOFILE, &rlp)) { + syslog(LOG_WARNING, "setrlimit(RLIMIT_NOFILE) failed: %s", + strerror(errno)); + } + } + my_svc_run(); /* Should never return */ exit(1); } @@ -265,7 +306,7 @@ init_nsm(void) ret = callrpc("localhost", SM_PROG, SM_VERS, SM_UNMON_ALL, xdr_my_id, &id, xdr_sm_stat, &stat); if (ret) { - warnx("%lu %s", SM_PROG, clnt_sperrno(ret)); + syslog(LOG_WARNING, "%lu %s", SM_PROG, clnt_sperrno(ret)); if (++attempt < 20) { sleep(attempt); continue; @@ -275,7 +316,8 @@ init_nsm(void) } while (1); if (ret != 0) { - errx(1, "%lu %s", SM_PROG, clnt_sperrno(ret)); + syslog(LOG_ERR, "%lu %s", SM_PROG, clnt_sperrno(ret)); + exit(1); } nsm_state = stat.state; diff --git a/rpc_lockd.tproj/lockd_lock.c b/rpc_lockd.tproj/lockd_lock.c index 29a77c5..1d69479 100644 --- a/rpc_lockd.tproj/lockd_lock.c +++ b/rpc_lockd.tproj/lockd_lock.c @@ -64,11 +64,6 @@ #define MAXOBJECTSIZE 64 #define MAXBUFFERSIZE 1024 -/* - * SM_MAXSTRLEN is usually 1024. This means that lock requests and - * host name monitoring entries are *MUCH* larger than they should be - */ - /* * A set of utilities for managing file locking * @@ -83,13 +78,11 @@ struct file_lock { struct sockaddr *addr; struct nlm4_holder client; /* lock holder */ u_int64_t granted_cookie; - char client_name[SM_MAXSTRLEN]; int nsm_status; /* status from the remote lock manager */ int status; /* lock status, see below */ int flags; /* lock flags, see lockd_lock.h */ int blocking; /* blocking lock or not */ - pid_t locker; /* pid of the child process trying to get the lock */ - int fd; /* file descriptor for this lock */ + char client_name[SM_MAXSTRLEN]; /* client_name is really variable length and must be last! */ }; LIST_HEAD(nfslocklist_head, file_lock); @@ -102,9 +95,9 @@ struct blockedlocklist_head blockedlocklist_head = LIST_HEAD_INITIALIZER(blocked struct file_share { LIST_ENTRY(file_share) nfssharelist; netobj oh; /* share holder */ - char client_name[SM_MAXSTRLEN]; short mode; short access; + char client_name[SM_MAXSTRLEN]; /* name is really variable length and must be last! */ }; LIST_HEAD(nfssharelist_head, file_share); @@ -129,9 +122,10 @@ struct nfssharefilelist_head nfssharefilelist_head = LIST_HEAD_INITIALIZER(nfssh /* struct describing a monitored host */ struct host { TAILQ_ENTRY(host) hostlst; - char name[SM_MAXSTRLEN]; int refcnt; time_t lastuse; + struct sockaddr addr; + char name[SM_MAXSTRLEN]; /* name is really variable length and must be last! */ }; /* list of hosts we monitor */ TAILQ_HEAD(hostlst_head, host); @@ -187,17 +181,17 @@ int send_granted(struct file_lock *fl, int opcode); void siglock(void); void sigunlock(void); void destroy_lock_host(struct host *ihp); -void monitor_lock_host(const char *hostname); -void unmonitor_lock_host(const char *hostname); +static void monitor_lock_host(const char *hostname, const struct sockaddr *addr); void copy_nlm4_lock_to_nlm4_holder(const struct nlm4_lock *src, const bool_t exclusive, struct nlm4_holder *dest); struct file_lock * allocate_file_lock(const netobj *lockowner, - const netobj *filehandle); + const netobj *filehandle, const struct sockaddr *addr, + const char *caller_name); void deallocate_file_lock(struct file_lock *fl); void fill_file_lock(struct file_lock *fl, - struct sockaddr *addr, const bool_t exclusive, const int32_t svid, - const u_int64_t offset, const u_int64_t len, const char *caller_name, + const bool_t exclusive, const int32_t svid, + const u_int64_t offset, const u_int64_t len, const int state, const int status, const int flags, const int blocking); int regions_overlap(const u_int64_t start1, const u_int64_t len1, const u_int64_t start2, const u_int64_t len2);; @@ -397,20 +391,40 @@ copy_nlm4_lock_to_nlm4_holder(src, exclusive, dest) } +size_t +strnlen(const char *s, size_t len) +{ + size_t n; + + for (n = 0; s[n] != 0 && n < len; n++) + ; + return n; +} + /* * allocate_file_lock: Create a lock with the given parameters */ struct file_lock * -allocate_file_lock(const netobj *lockowner, const netobj *filehandle) +allocate_file_lock(const netobj *lockowner, const netobj *filehandle, + const struct sockaddr *addr, const char *caller_name) { struct file_lock *newfl; + size_t n; + + /* Beware of rubbish input! */ + n = strnlen(caller_name, SM_MAXSTRLEN); + if (n == SM_MAXSTRLEN) { + return NULL; + } - newfl = malloc(sizeof(struct file_lock)); + newfl = malloc(sizeof(*newfl) - sizeof(newfl->client_name) + n + 1); if (newfl == NULL) { return NULL; } - bzero(newfl, sizeof(newfl)); + bzero(newfl, sizeof(*newfl) - sizeof(newfl->client_name)); + memcpy(newfl->client_name, caller_name, n); + newfl->client_name[n] = 0; newfl->client.oh.n_bytes = malloc(lockowner->n_len); if (newfl->client.oh.n_bytes == NULL) { @@ -429,6 +443,14 @@ allocate_file_lock(const netobj *lockowner, const netobj *filehandle) newfl->filehandle.n_len = filehandle->n_len; bcopy(filehandle->n_bytes, newfl->filehandle.n_bytes, filehandle->n_len); + newfl->addr = malloc(addr->sa_len); + if (newfl->addr == NULL) { + free(newfl->client.oh.n_bytes); + free(newfl); + return NULL; + } + memcpy(newfl->addr, addr, addr->sa_len); + return newfl; } @@ -437,19 +459,15 @@ allocate_file_lock(const netobj *lockowner, const netobj *filehandle) */ void fill_file_lock(struct file_lock *fl, - struct sockaddr *addr, const bool_t exclusive, const int32_t svid, - const u_int64_t offset, const u_int64_t len, const char *caller_name, + const bool_t exclusive, const int32_t svid, + const u_int64_t offset, const u_int64_t len, const int state, const int status, const int flags, const int blocking) { - fl->addr = addr; - fl->client.exclusive = exclusive; fl->client.svid = svid; fl->client.l_offset = offset; fl->client.l_len = len; - strncpy(fl->client_name, caller_name, SM_MAXSTRLEN); - fl->nsm_status = state; fl->status = status; fl->flags = flags; @@ -462,6 +480,7 @@ fill_file_lock(struct file_lock *fl, void deallocate_file_lock(struct file_lock *fl) { + free(fl->addr); free(fl->client.oh.n_bytes); free(fl->filehandle.n_bytes); free(fl); @@ -948,22 +967,21 @@ split_nfslock(exist_lock, unlock_lock, left_lock, right_lock) &start1, &len1, &start2, &len2); if ((spstatus & SPL_LOCK1) != 0) { - *left_lock = allocate_file_lock(&exist_lock->client.oh, &exist_lock->filehandle); + *left_lock = allocate_file_lock(&exist_lock->client.oh, &exist_lock->filehandle, exist_lock->addr, exist_lock->client_name); if (*left_lock == NULL) { debuglog("Unable to allocate resource for split 1\n"); return SPL_RESERR; } fill_file_lock(*left_lock, - exist_lock->addr, exist_lock->client.exclusive, exist_lock->client.svid, start1, len1, - exist_lock->client_name, exist_lock->nsm_status, + exist_lock->nsm_status, exist_lock->status, exist_lock->flags, exist_lock->blocking); } if ((spstatus & SPL_LOCK2) != 0) { - *right_lock = allocate_file_lock(&exist_lock->client.oh, &exist_lock->filehandle); + *right_lock = allocate_file_lock(&exist_lock->client.oh, &exist_lock->filehandle, exist_lock->addr, exist_lock->client_name); if (*right_lock == NULL) { debuglog("Unable to allocate resource for split 1\n"); if (*left_lock != NULL) { @@ -973,10 +991,9 @@ split_nfslock(exist_lock, unlock_lock, left_lock, right_lock) } fill_file_lock(*right_lock, - exist_lock->addr, exist_lock->client.exclusive, exist_lock->client.svid, start2, len2, - exist_lock->client_name, exist_lock->nsm_status, + exist_lock->nsm_status, exist_lock->status, exist_lock->flags, exist_lock->blocking); } @@ -1002,7 +1019,7 @@ unlock_nfslock(fl, released_lock, left_lock, right_lock) retval = NFS_DENIED_NOLOCK; - printf("Attempting to match lock...\n"); + debuglog("Attempting to match lock...\n"); mfl = get_lock_matching_unlock(fl); if (mfl != NULL) { @@ -1091,7 +1108,7 @@ lock_hwlock(struct file_lock *fl) return (HW_RESERR); } nmf->filehandle.n_bytes = malloc(fl->filehandle.n_len); - if (nmf == NULL) { + if (nmf->filehandle.n_bytes == NULL) { debuglog("hwlock resource allocation failure\n"); free(nmf); return (HW_RESERR); @@ -1102,6 +1119,7 @@ lock_hwlock(struct file_lock *fl) if (nmf->fd < 0) { debuglog("fhopen failed (from %16s): %32s\n", fl->client_name, strerror(errno)); + free(nmf->filehandle.n_bytes); free(nmf); switch (errno) { case ESTALE: @@ -1128,6 +1146,7 @@ lock_hwlock(struct file_lock *fl) debuglog("flock failed (from %16s): %32s\n", fl->client_name, strerror(errno)); close(nmf->fd); + free(nmf->filehandle.n_bytes); free(nmf); switch (errno) { case EAGAIN: @@ -1185,6 +1204,7 @@ unlock_hwlock(const struct file_lock *fl) if (imf->refcount <= 0) { close(imf->fd); LIST_REMOVE(imf, monfilelist); + free(imf->filehandle.n_bytes); free(imf); } debuglog("Exiting unlock_hwlock (HW_GRANTED)\n"); @@ -1463,7 +1483,7 @@ lock_partialfilelock(struct file_lock *fl) retval = PFL_GRANTED; } if (fl->flags & LOCK_MON) - monitor_lock_host(fl->client_name); + monitor_lock_host_by_name(fl->client_name); break; case HW_RESERR: debuglog("HW RESERR\n"); @@ -1505,12 +1525,17 @@ lock_partialfilelock(struct file_lock *fl) if (retval == PFL_NFSDENIED || retval == PFL_HWDENIED) { /* Once last chance to check the lock */ if (fl->blocking == 1) { - /* Queue the lock */ - debuglog("BLOCKING LOCK RECEIVED\n"); - retval = (retval == PFL_NFSDENIED ? - PFL_NFSBLOCKED : PFL_HWBLOCKED); - add_blockingfilelock(fl); - dump_filelock(fl); + if (retval == PFL_NFSDENIED) { + /* Queue the lock */ + debuglog("BLOCKING LOCK RECEIVED\n"); + retval = PFL_NFSBLOCKED; + add_blockingfilelock(fl); + dump_filelock(fl); + } else { + /* retval is okay as PFL_HWDENIED */ + debuglog("BLOCKING LOCK DENIED IN HARDWARE\n"); + dump_filelock(fl); + } } else { /* Leave retval alone, it's already correct */ debuglog("Lock denied. Non-blocking failure\n"); @@ -1585,7 +1610,7 @@ unlock_partialfilelock(const struct file_lock *fl) debuglog("HW duplicate lock failure for left split\n"); } if (lfl->flags & LOCK_MON) - monitor_lock_host(lfl->client_name); + monitor_lock_host_by_name(lfl->client_name); } if (rfl != NULL) { @@ -1595,7 +1620,7 @@ unlock_partialfilelock(const struct file_lock *fl) debuglog("HW duplicate lock failure for right split\n"); } if (rfl->flags & LOCK_MON) - monitor_lock_host(rfl->client_name); + monitor_lock_host_by_name(rfl->client_name); } switch (unlstatus) { @@ -2003,7 +2028,9 @@ getlock(nlm4_lockargs *lckarg, struct svc_req *rqstp, const int flags) nlm4_denied_grace_period : nlm_denied_grace_period; /* allocate new file_lock for this request */ - newfl = allocate_file_lock(&lckarg->alock.oh, &lckarg->alock.fh); + newfl = allocate_file_lock(&lckarg->alock.oh, &lckarg->alock.fh, + (struct sockaddr *)svc_getcaller(rqstp->rq_xprt), + lckarg->alock.caller_name); if (newfl == NULL) { syslog(LOG_NOTICE, "lock allocate failed: %s", strerror(errno)); /* failed */ @@ -2017,10 +2044,9 @@ getlock(nlm4_lockargs *lckarg, struct svc_req *rqstp, const int flags) } fill_file_lock(newfl, - (struct sockaddr *)svc_getcaller(rqstp->rq_xprt), lckarg->exclusive, lckarg->alock.svid, lckarg->alock.l_offset, lckarg->alock.l_len, - lckarg->alock.caller_name, lckarg->state, 0, flags, lckarg->block); + lckarg->state, 0, flags, lckarg->block); /* * newfl is now fully constructed and deallocate_file_lock @@ -2152,7 +2178,7 @@ cancellock(nlm4_cancargs *args, const int flags __unused) /* * XXX: The following monitor/unmonitor routines * have not been extensively tested (ie. no regression - * script exists like for the locking sections + * script exists like for the locking sections) */ /* @@ -2163,24 +2189,38 @@ cancellock(nlm4_cancargs *args, const int flags __unused) * enqueue it at the front of the "in use" queue. */ struct host * -get_lock_host(struct hostlst_head *hd, const char *hostname) +get_lock_host(struct hostlst_head *hd, const char *hostname, const struct sockaddr *saddr) { struct host *ihp; - debuglog("get_lock_host %s\n", hostname); + if (!hostname && !saddr) + return (NULL); + + debuglog("get_lock_host %s\n", hostname ? hostname : "addr"); TAILQ_FOREACH(ihp, hd, hostlst) { - if (strncmp(hostname, ihp->name, SM_MAXSTRLEN) == 0) { - TAILQ_REMOVE(hd, ihp, hostlst); - /* Host is already monitored, bump refcount */ + if (hostname && (strncmp(hostname, ihp->name, SM_MAXSTRLEN) != 0)) + continue; + if (saddr && addrcmp(saddr, &ihp->addr)) + continue; + TAILQ_REMOVE(hd, ihp, hostlst); + /* + * Host is already monitored, so just bump the + * reference count. But don't bump the reference + * count if we're adding additional client-side + * references. Client-side monitors are done by + * address, are never unmonitored, and should only + * take one refcount. Otherwise, repeated calls + * could cause the refcount to wrap. + */ + if (!saddr || !ihp->addr.sa_len) ++ihp->refcnt; - ihp->lastuse = currsec; - /* Host should only be in the monitor list once */ - TAILQ_INSERT_HEAD(&hostlst_head, ihp, hostlst); - break; - } + ihp->lastuse = currsec; + /* Host should only be in the monitor list once */ + TAILQ_INSERT_HEAD(&hostlst_head, ihp, hostlst); + break; } debuglog("get_lock_host %s %s\n", - ihp == NULL ? "did not find" : "found", hostname); + ihp == NULL ? "did not find" : "found", hostname ? hostname : "addr"); return (ihp); } @@ -2189,39 +2229,89 @@ get_lock_host(struct hostlst_head *hd, const char *hostname) * inform statd */ void -monitor_lock_host(const char *hostname) +monitor_lock_host_by_name(const char *hostname) { - struct host *ihp, *nhp; - struct mon smon; - struct sm_stat_res sres; - int rpcret, statflag; - - rpcret = 0; - statflag = 0; + struct host *ihp; debuglog("monitor_lock_host: %s\n", hostname); - ihp = get_lock_host(&hostlst_head, hostname); + ihp = get_lock_host(&hostlst_head, hostname, NULL); if (ihp == NULL) - ihp = get_lock_host(&hostlst_unref, hostname); + ihp = get_lock_host(&hostlst_unref, hostname, NULL); if (ihp != NULL) { debuglog("Monitor_lock_host: %s (cached)\n", hostname); return; } - debuglog("Monitor_lock_host: %s (not found, creating)\n", hostname); - /* Host is not yet monitored, add it */ - nhp = malloc(sizeof(struct host)); + monitor_lock_host(hostname, NULL); +} + +void +monitor_lock_host_by_addr(const struct sockaddr *saddr) +{ + struct host *ihp; + struct hostent *hp; + char hostaddr[SM_MAXSTRLEN]; + struct sockaddr_in *sin = (struct sockaddr_in *)saddr; + if (getnameinfo(saddr, saddr->sa_len, hostaddr, sizeof(hostaddr), + NULL, 0, NI_NUMERICHOST)) { + debuglog("monitor_lock_host: bad address\n"); + return; + } + debuglog("monitor_lock_host: %s\n", hostaddr); + ihp = get_lock_host(&hostlst_head, NULL, saddr); + if (ihp == NULL) + ihp = get_lock_host(&hostlst_unref, NULL, saddr); + if (ihp != NULL) { + debuglog("Monitor_lock_host: %s (cached)\n", ihp->name); + return; + } + + hp = gethostbyaddr((char*)&sin->sin_addr, sizeof(sin->sin_addr), AF_INET); + if (hp) { + monitor_lock_host(hp->h_name, saddr); + } else { + // herror(hostaddr); + monitor_lock_host(hostaddr, saddr); + } +} + +static void +monitor_lock_host(const char *hostname, const struct sockaddr *saddr) +{ + struct host *nhp; + struct mon smon; + struct sm_stat_res sres; + int rpcret, statflag; + size_t n; + + rpcret = 0; + statflag = 0; + + /* Host is not yet monitored, add it */ + debuglog("Monitor_lock_host: %s (creating)\n", hostname); + n = strnlen(hostname, SM_MAXSTRLEN); + if (n == SM_MAXSTRLEN) { + debuglog("monitor_lock_host: hostname too long\n"); + return; + } + nhp = malloc(sizeof(*nhp) - sizeof(nhp->name) + n + 1); if (nhp == NULL) { debuglog("Unable to allocate entry for statd mon\n"); return; } /* Allocated new host entry, now fill the fields */ - strncpy(nhp->name, hostname, SM_MAXSTRLEN); + memcpy(nhp->name, hostname, n); + nhp->name[n] = 0; nhp->refcnt = 1; nhp->lastuse = currsec; - debuglog("Locally Monitoring host %16s\n",hostname); + if (saddr) { + bcopy(saddr, &nhp->addr, saddr->sa_len); + } else { + nhp->addr.sa_len = 0; + } + debuglog("Locally Monitoring host '%s'\n", hostname); debuglog("Attempting to tell statd\n"); @@ -2267,7 +2357,7 @@ unmonitor_lock_host(const char *hostname) TAILQ_FOREACH(ihp, &hostlst_head, hostlst) { if (strncmp(hostname, ihp->name, SM_MAXSTRLEN) == 0) { - /* Host is monitored, bump refcount */ + /* Host is unmonitored, drop refcount */ --ihp->refcnt; /* Host should only be in the monitor list once */ break; @@ -2514,6 +2604,7 @@ getshare(nlm_shareargs *shrarg, struct svc_req *rqstp, const int flags) { struct sharefile *shrfile; struct file_share *sh; + size_t n; debuglog("Entering getshare...\n"); @@ -2592,7 +2683,13 @@ getshare(nlm_shareargs *shrarg, struct svc_req *rqstp, const int flags) } /* create/init new share */ - sh = malloc(sizeof(struct file_share)); + n = strnlen(shrarg->share.caller_name, SM_MAXSTRLEN); + if (n < SM_MAXSTRLEN) { + sh = malloc(sizeof(*sh) - sizeof(sh->client_name) + n + 1); + } else { + debuglog("getshare failed: hostname too long\n"); + sh = NULL; + } if (!sh) { debuglog("getshare failed: can't allocate share\n"); if (!shrfile->refcount) { @@ -2603,6 +2700,7 @@ getshare(nlm_shareargs *shrarg, struct svc_req *rqstp, const int flags) } return (flags & LOCK_V4) ? nlm4_failed : nlm_denied; } + bzero(sh, sizeof(*sh) - sizeof(sh->client_name)); sh->oh.n_len = shrarg->share.oh.n_len; sh->oh.n_bytes = malloc(sh->oh.n_len); if (!sh->oh.n_bytes) { @@ -2616,7 +2714,8 @@ getshare(nlm_shareargs *shrarg, struct svc_req *rqstp, const int flags) } return (flags & LOCK_V4) ? nlm4_failed : nlm_denied; } - strncpy(sh->client_name, shrarg->share.caller_name, SM_MAXSTRLEN); + memcpy(sh->client_name, shrarg->share.caller_name, n); + sh->client_name[n] = 0; sh->mode = shrarg->share.mode; sh->access = shrarg->share.access; diff --git a/rpc_lockd.tproj/lockd_lock.h b/rpc_lockd.tproj/lockd_lock.h index 4d93c7d..ca1aa37 100644 --- a/rpc_lockd.tproj/lockd_lock.h +++ b/rpc_lockd.tproj/lockd_lock.h @@ -17,6 +17,10 @@ void granted_failed(nlm4_res *arg); void notify(const char *hostname, const int state); +void monitor_lock_host_by_name(const char *hostname); +void monitor_lock_host_by_addr(const struct sockaddr *addr); +void unmonitor_lock_host(const char *hostname); + /* flags for testlock, getlock & unlock */ #define LOCK_ASYNC 0x01 /* async version (getlock only) */ #define LOCK_V4 0x02 /* v4 version */ @@ -27,9 +31,10 @@ void notify(const char *hostname, const int state); #define LOCK_ANSWER_LOCK_EXCL 0x0004 /* lock is exclusive */ /* callbacks from lock_proc.c */ -void transmit_result(int, nlm_res *, struct sockaddr *); -void transmit4_result(int, nlm4_res *, struct sockaddr *); +int transmit_result(int, nlm_res *, struct sockaddr *); +int transmit4_result(int, nlm4_res *, struct sockaddr *); CLIENT *get_client(struct sockaddr *, rpcvers_t); +int addrcmp(const struct sockaddr *, const struct sockaddr *); extern time_t currsec; diff --git a/rpc_statd.tproj/procs.c b/rpc_statd.tproj/procs.c index 74aed60..c564094 100644 --- a/rpc_statd.tproj/procs.c +++ b/rpc_statd.tproj/procs.c @@ -381,9 +381,33 @@ void *sm_notify_1_svc(stat_chge *arg, struct svc_req *req __unused) hp = find_host(arg->mon_name, FALSE); if (!hp) { - /* Never heard of this host - why is it notifying us? */ - syslog(LOG_ERR, "Unsolicited notification from host %s", arg->mon_name); - return (&dummy); + /* + * Hmmm... We've never heard of this host. + * It's possible the host just didn't give us the right hostname. + * Let's try the IP address the request came from and any hostnames it has. + */ + struct sockaddr_in *claddr; + if ((claddr = svc_getcaller(req->rq_xprt))) { + struct hostent *he; + he = gethostbyaddr((char*)&claddr->sin_addr, sizeof(claddr->sin_addr), AF_INET); + if (he) { + char **np = he->h_aliases; + hp = find_host(he->h_name, FALSE); + while (!hp && *np) { + hp = find_host(*np, FALSE); + if (!hp) + np++; + } + } + if (hp) + syslog(LOG_DEBUG, "Notification from host %s found as %s", + arg->mon_name, hp->hostname); + } + if (!hp) { + /* Never heard of this host - why is it notifying us? */ + syslog(LOG_DEBUG, "Unsolicited notification from host %s", arg->mon_name); + return (&dummy); + } } lp = hp->monList; if (!lp) return (&dummy); /* We know this host, but have no */ @@ -398,7 +422,7 @@ void *sm_notify_1_svc(stat_chge *arg, struct svc_req *req __unused) while (lp) { - tx_arg.mon_name = arg->mon_name; + tx_arg.mon_name = hp->hostname; tx_arg.state = arg->state; memcpy(tx_arg.priv, lp->notifyData, sizeof(tx_arg.priv)); cli = clnt_create(lp->notifyHost, lp->notifyProg, lp->notifyVers, "udp"); -- 2.45.2