Home | History | Annotate | Line # | Download | only in rpc.lockd
      1 /*	$NetBSD: lock_proc.c,v 1.10 2012/06/18 20:30:32 tron Exp $	*/
      2 
      3 /*
      4  * Copyright (c) 1995
      5  *	A.R. Gordon (andrew.gordon (at) net-tel.co.uk).  All rights reserved.
      6  *
      7  * Redistribution and use in source and binary forms, with or without
      8  * modification, are permitted provided that the following conditions
      9  * are met:
     10  * 1. Redistributions of source code must retain the above copyright
     11  *    notice, this list of conditions and the following disclaimer.
     12  * 2. Redistributions in binary form must reproduce the above copyright
     13  *    notice, this list of conditions and the following disclaimer in the
     14  *    documentation and/or other materials provided with the distribution.
     15  * 3. All advertising materials mentioning features or use of this software
     16  *    must display the following acknowledgement:
     17  *	This product includes software developed for the FreeBSD project
     18  * 4. Neither the name of the author nor the names of any co-contributors
     19  *    may be used to endorse or promote products derived from this software
     20  *    without specific prior written permission.
     21  *
     22  * THIS SOFTWARE IS PROVIDED BY ANDREW GORDON AND CONTRIBUTORS ``AS IS'' AND
     23  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     24  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     25  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
     26  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     27  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     28  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     29  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     30  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     31  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     32  * SUCH DAMAGE.
     33  *
     34  */
     35 
     36 #include <sys/cdefs.h>
     37 #ifndef lint
     38 __RCSID("$NetBSD: lock_proc.c,v 1.10 2012/06/18 20:30:32 tron Exp $");
     39 #endif
     40 
     41 #include <sys/param.h>
     42 #include <sys/socket.h>
     43 
     44 #include <netinet/in.h>
     45 #include <arpa/inet.h>
     46 
     47 #include <netdb.h>
     48 #include <stdio.h>
     49 #include <string.h>
     50 #include <syslog.h>
     51 #include <netconfig.h>
     52 
     53 #include <rpc/rpc.h>
     54 #include <rpcsvc/sm_inter.h>
     55 
     56 #include "lockd.h"
     57 #include <rpcsvc/nlm_prot.h>
     58 #include "lockd_lock.h"
     59 
     60 
     61 #define	CLIENT_CACHE_SIZE	64	/* No. of client sockets cached */
     62 #define	CLIENT_CACHE_LIFETIME	120	/* In seconds */
     63 
     64 static void	log_from_addr(const char *, struct svc_req *);
     65 static int	addrcmp(const struct sockaddr *, const struct sockaddr *);
     66 static void	nlmtonlm4(struct nlm_lock *, struct nlm4_lock *);
     67 
     68 /* log_from_addr ----------------------------------------------------------- */
     69 /*
     70  * Purpose:	Log name of function called and source address
     71  * Returns:	Nothing
     72  * Notes:	Extracts the source address from the transport handle
     73  *		passed in as part of the called procedure specification
     74  */
     75 static void
     76 log_from_addr(const char *fun_name, struct svc_req *req)
     77 {
     78 	struct sockaddr *addr;
     79 	char hostname_buf[NI_MAXHOST];
     80 
     81 	addr = svc_getrpccaller(req->rq_xprt)->buf;
     82 	if (getnameinfo(addr, (socklen_t)addr->sa_len, hostname_buf,
     83 	    sizeof(hostname_buf), NULL, 0, 0) != 0)
     84 		return;
     85 
     86 	syslog(LOG_DEBUG, "%s from %s", fun_name, hostname_buf);
     87 }
     88 
     89 /* get_client -------------------------------------------------------------- */
     90 /*
     91  * Purpose:	Get a CLIENT* for making RPC calls to lockd on given host
     92  * Returns:	CLIENT* pointer, from clnt_udp_create, or NULL if error
     93  * Notes:	Creating a CLIENT* is quite expensive, involving a
     94  *		conversation with the remote portmapper to get the
     95  *		port number.  Since a given client is quite likely
     96  *		to make several locking requests in succession, it is
     97  *		desirable to cache the created CLIENT*.
     98  *
     99  *		Since we are using UDP rather than TCP, there is no cost
    100  *		to the remote system in keeping these cached indefinitely.
    101  *		Unfortunately there is a snag: if the remote system
    102  *		reboots, the cached portmapper results will be invalid,
    103  *		and we will never detect this since all of the xxx_msg()
    104  *		calls return no result - we just fire off a udp packet
    105  *		and hope for the best.
    106  *
    107  *		We solve this by discarding cached values after two
    108  *		minutes, regardless of whether they have been used
    109  *		in the meanwhile (since a bad one might have been used
    110  *		plenty of times, as the host keeps retrying the request
    111  *		and we keep sending the reply back to the wrong port).
    112  *
    113  *		Given that the entries will always expire in the order
    114  *		that they were created, there is no point in a LRU
    115  *		algorithm for when the cache gets full - entries are
    116  *		always re-used in sequence.
    117  */
    118 static CLIENT *clnt_cache_ptr[CLIENT_CACHE_SIZE];
    119 static long clnt_cache_time[CLIENT_CACHE_SIZE];	/* time entry created */
    120 static struct sockaddr_storage clnt_cache_addr[CLIENT_CACHE_SIZE];
    121 static int clnt_cache_next_to_use = 0;
    122 
    123 static int
    124 addrcmp(const struct sockaddr *sa1, const struct sockaddr *sa2)
    125 {
    126 	size_t len;
    127 	const void *p1, *p2;
    128 
    129 	if (sa1->sa_family != sa2->sa_family)
    130 		return -1;
    131 
    132 	switch (sa1->sa_family) {
    133 	case AF_INET:
    134 		p1 = &((const struct sockaddr_in *)(const void *)sa1)->sin_addr;
    135 		p2 = &((const struct sockaddr_in *)(const void *)sa2)->sin_addr;
    136 		len = 4;
    137 		break;
    138 	case AF_INET6:
    139 		p1 = &((const struct sockaddr_in6 *)(const void *)sa1)->sin6_addr;
    140 		p2 = &((const struct sockaddr_in6 *)(const void *)sa2)->sin6_addr;
    141 		len = 16;
    142 		break;
    143 	default:
    144 		return -1;
    145 	}
    146 
    147 	return memcmp(p1, p2, len);
    148 }
    149 
    150 CLIENT *
    151 get_client(struct sockaddr *host_addr, rpcvers_t vers)
    152 {
    153 	CLIENT *client;
    154 	struct timeval retry_time, time_now;
    155 	int i;
    156 	const char *netid;
    157 	struct netconfig *nconf;
    158 	char host[NI_MAXHOST];
    159 	int error;
    160 
    161 	(void)gettimeofday(&time_now, NULL);
    162 
    163 	/*
    164 	 * Search for the given client in the cache, zapping any expired
    165 	 * entries that we happen to notice in passing.
    166 	 */
    167 	for (i = 0; i < CLIENT_CACHE_SIZE; i++) {
    168 		client = clnt_cache_ptr[i];
    169 		if (client && ((clnt_cache_time[i] + CLIENT_CACHE_LIFETIME)
    170 		    < time_now.tv_sec)) {
    171 			/* Cache entry has expired. */
    172 			if (debug_level > 3)
    173 				syslog(LOG_DEBUG, "Expired CLIENT* in cache");
    174 			clnt_cache_time[i] = 0L;
    175 			clnt_destroy(client);
    176 			clnt_cache_ptr[i] = NULL;
    177 			client = NULL;
    178 		}
    179 		if (client && !addrcmp((const struct sockaddr *)(const void *)
    180 		    &clnt_cache_addr[i], host_addr)) {
    181 			/* Found it! */
    182 			if (debug_level > 3)
    183 				syslog(LOG_DEBUG, "Found CLIENT* in cache");
    184 			return client;
    185 		}
    186 	}
    187 
    188 	/* Not found in cache.  Free the next entry if it is in use. */
    189 	if (clnt_cache_ptr[clnt_cache_next_to_use]) {
    190 		clnt_destroy(clnt_cache_ptr[clnt_cache_next_to_use]);
    191 		clnt_cache_ptr[clnt_cache_next_to_use] = NULL;
    192 	}
    193 
    194 	/*
    195 	 * Need a host string for clnt_tp_create. Use NI_NUMERICHOST
    196 	 * to avoid DNS lookups.
    197 	 */
    198 	error = getnameinfo(host_addr, (socklen_t)host_addr->sa_len, host,
    199 	    sizeof(host), NULL, 0, NI_NUMERICHOST);
    200 	if (error != 0) {
    201 		syslog(LOG_ERR, "unable to get name string for caller: %s",
    202 		    gai_strerror(error));
    203 		return NULL;
    204 	}
    205 
    206 #if 1
    207 	if (host_addr->sa_family == AF_INET6)
    208 		netid = "udp6";
    209 	else
    210 		netid = "udp";
    211 #else
    212 	if (host_addr->sa_family == AF_INET6)
    213 		netid = "tcp6";
    214 	else
    215 		netid = "tcp";
    216 #endif
    217 	nconf = getnetconfigent(netid);
    218 	if (nconf == NULL) {
    219 		syslog(LOG_ERR, "could not get netconfig info for '%s': "
    220 				"no /etc/netconfig file?", netid);
    221 		return NULL;
    222 	}
    223 
    224 	client = clnt_tp_create(host, NLM_PROG, vers, nconf);
    225 	freenetconfigent(nconf);
    226 
    227 	if (!client) {
    228 		syslog(LOG_ERR, "%s", clnt_spcreateerror("clntudp_create"));
    229 		syslog(LOG_ERR, "Unable to return result to %s", host);
    230 		return NULL;
    231 	}
    232 
    233 	/* Success - update the cache entry */
    234 	clnt_cache_ptr[clnt_cache_next_to_use] = client;
    235 	(void)memcpy(&clnt_cache_addr[clnt_cache_next_to_use], host_addr,
    236 	    (size_t)host_addr->sa_len);
    237 	clnt_cache_time[clnt_cache_next_to_use] = time_now.tv_sec;
    238 	if (++clnt_cache_next_to_use >= CLIENT_CACHE_SIZE)
    239 		clnt_cache_next_to_use = 0;
    240 
    241 	/*
    242 	 * Disable the default timeout, so we can specify our own in calls
    243 	 * to clnt_call().  (Note that the timeout is a different concept
    244 	 * from the retry period set in clnt_udp_create() above.)
    245 	 */
    246 	retry_time.tv_sec = -1;
    247 	retry_time.tv_usec = -1;
    248 	clnt_control(client, CLSET_TIMEOUT, (char *)(void *)&retry_time);
    249 
    250 	if (debug_level > 3)
    251 		syslog(LOG_DEBUG, "Created CLIENT* for %s", host);
    252 	return client;
    253 }
    254 
    255 
    256 /* transmit_result --------------------------------------------------------- */
    257 /*
    258  * Purpose:	Transmit result for nlm_xxx_msg pseudo-RPCs
    259  * Returns:	Nothing - we have no idea if the datagram got there
    260  * Notes:	clnt_call() will always fail (with timeout) as we are
    261  *		calling it with timeout 0 as a hack to just issue a datagram
    262  *		without expecting a result
    263  */
    264 void
    265 transmit_result(int opcode, nlm_res *result, struct sockaddr *addr)
    266 {
    267 	static char dummy;
    268 	CLIENT *cli;
    269 	struct timeval timeo;
    270 	int success;
    271 
    272 	if ((cli = get_client(addr, NLM_VERS)) != NULL) {
    273 		timeo.tv_sec = 0; /* No timeout - not expecting response */
    274 		timeo.tv_usec = 0;
    275 
    276 		success = clnt_call(cli, (rpcproc_t)opcode, xdr_nlm_res,
    277 		    result, xdr_void, &dummy, timeo);
    278 
    279 		if (debug_level > 2)
    280 			syslog(LOG_DEBUG, "clnt_call returns %d(%s)",
    281 			    success, clnt_sperrno(success));
    282 	}
    283 }
    284 /* transmit4_result --------------------------------------------------------- */
    285 /*
    286  * Purpose:	Transmit result for nlm4_xxx_msg pseudo-RPCs
    287  * Returns:	Nothing - we have no idea if the datagram got there
    288  * Notes:	clnt_call() will always fail (with timeout) as we are
    289  *		calling it with timeout 0 as a hack to just issue a datagram
    290  *		without expecting a result
    291  */
    292 void
    293 transmit4_result(int opcode, nlm4_res *result, struct sockaddr *addr)
    294 {
    295 	static char dummy;
    296 	CLIENT *cli;
    297 	struct timeval timeo;
    298 	int success;
    299 
    300 	if ((cli = get_client(addr, NLM_VERS4)) != NULL) {
    301 		timeo.tv_sec = 0; /* No timeout - not expecting response */
    302 		timeo.tv_usec = 0;
    303 
    304 		success = clnt_call(cli, (rpcproc_t)opcode, xdr_nlm4_res,
    305 		    result, xdr_void, &dummy, timeo);
    306 
    307 		if (debug_level > 2)
    308 			syslog(LOG_DEBUG, "clnt_call returns %d(%s)",
    309 			    success, clnt_sperrno(success));
    310 	}
    311 }
    312 
    313 /*
    314  * converts a struct nlm_lock to struct nlm4_lock
    315  */
    316 static void
    317 nlmtonlm4(struct nlm_lock *arg, struct nlm4_lock *arg4)
    318 {
    319 	(void)memcpy(arg4, arg, sizeof(nlm_lock));
    320 	arg4->l_offset = arg->l_offset;
    321 	arg4->l_len = arg->l_len;
    322 }
    323 
    324 /* ------------------------------------------------------------------------- */
    325 /*
    326  * Functions for Unix<->Unix locking (ie. monitored locking, with rpc.statd
    327  * involved to ensure reclaim of locks after a crash of the "stateless"
    328  * server.
    329  *
    330  * These all come in two flavours - nlm_xxx() and nlm_xxx_msg().
    331  * The first are standard RPCs with argument and result.
    332  * The nlm_xxx_msg() calls implement exactly the same functions, but
    333  * use two pseudo-RPCs (one in each direction).  These calls are NOT
    334  * standard use of the RPC protocol in that they do not return a result
    335  * at all (NB. this is quite different from returning a void result).
    336  * The effect of this is to make the nlm_xxx_msg() calls simple unacknowledged
    337  * datagrams, requiring higher-level code to perform retries.
    338  *
    339  * Despite the disadvantages of the nlm_xxx_msg() approach (some of which
    340  * are documented in the comments to get_client() above), this is the
    341  * interface used by all current commercial NFS implementations
    342  * [Solaris, SCO, AIX etc.].  This is presumed to be because these allow
    343  * implementations to continue using the standard RPC libraries, while
    344  * avoiding the block-until-result nature of the library interface.
    345  *
    346  * No client implementations have been identified so far that make use
    347  * of the true RPC version (early SunOS releases would be a likely candidate
    348  * for testing).
    349  */
    350 
    351 /* nlm_test ---------------------------------------------------------------- */
    352 /*
    353  * Purpose:	Test whether a specified lock would be granted if requested
    354  * Returns:	nlm_granted (or error code)
    355  * Notes:
    356  */
    357 nlm_testres *
    358 nlm_test_1_svc(nlm_testargs *arg, struct svc_req *rqstp)
    359 {
    360 	static nlm_testres result;
    361 	struct nlm4_lock arg4;
    362 	struct nlm4_holder *holder;
    363 	nlmtonlm4(&arg->alock, &arg4);
    364 
    365 	if (debug_level)
    366 		log_from_addr("nlm_test", rqstp);
    367 
    368 	holder = testlock(&arg4, 0);
    369 	/*
    370 	 * Copy the cookie from the argument into the result.  Note that this
    371 	 * is slightly hazardous, as the structure contains a pointer to a
    372 	 * malloc()ed buffer that will get freed by the caller.  However, the
    373 	 * main function transmits the result before freeing the argument
    374 	 * so it is in fact safe.
    375 	 */
    376 	result.cookie = arg->cookie;
    377 	if (holder == NULL) {
    378 		result.stat.stat = nlm_granted;
    379 	} else {
    380 		result.stat.stat = nlm_denied;
    381 		(void)memcpy(&result.stat.nlm_testrply_u.holder, holder,
    382 		    sizeof(struct nlm_holder));
    383 		result.stat.nlm_testrply_u.holder.l_offset =
    384 		    (unsigned int)holder->l_offset;
    385 		result.stat.nlm_testrply_u.holder.l_len =
    386 		    (unsigned int)holder->l_len;
    387 	}
    388 	return &result;
    389 }
    390 
    391 void *
    392 nlm_test_msg_1_svc(nlm_testargs *arg, struct svc_req *rqstp)
    393 {
    394 	nlm_testres result;
    395 	static char dummy;
    396 	struct sockaddr *addr;
    397 	CLIENT *cli;
    398 	int success;
    399 	struct timeval timeo;
    400 	struct nlm4_lock arg4;
    401 	struct nlm4_holder *holder;
    402 
    403 	nlmtonlm4(&arg->alock, &arg4);
    404 
    405 	if (debug_level)
    406 		log_from_addr("nlm_test_msg", rqstp);
    407 
    408 	holder = testlock(&arg4, 0);
    409 
    410 	result.cookie = arg->cookie;
    411 	if (holder == NULL) {
    412 		result.stat.stat = nlm_granted;
    413 	} else {
    414 		result.stat.stat = nlm_denied;
    415 		(void)memcpy(&result.stat.nlm_testrply_u.holder, holder,
    416 		    sizeof(struct nlm_holder));
    417 		result.stat.nlm_testrply_u.holder.l_offset =
    418 		    (unsigned int)holder->l_offset;
    419 		result.stat.nlm_testrply_u.holder.l_len =
    420 		    (unsigned int)holder->l_len;
    421 	}
    422 
    423 	/*
    424 	 * nlm_test has different result type to the other operations, so
    425 	 * can't use transmit_result() in this case
    426 	 */
    427 	addr = svc_getrpccaller(rqstp->rq_xprt)->buf;
    428 	if ((cli = get_client(addr, NLM_VERS)) != NULL) {
    429 		timeo.tv_sec = 0; /* No timeout - not expecting response */
    430 		timeo.tv_usec = 0;
    431 
    432 		success = clnt_call(cli, NLM_TEST_RES, xdr_nlm_testres,
    433 		    &result, xdr_void, &dummy, timeo);
    434 
    435 		if (debug_level > 2)
    436 			syslog(LOG_DEBUG, "clnt_call returns %d", success);
    437 	}
    438 	return NULL;
    439 }
    440 
    441 /* nlm_lock ---------------------------------------------------------------- */
    442 /*
    443  * Purposes:	Establish a lock
    444  * Returns:	granted, denied or blocked
    445  * Notes:	*** grace period support missing
    446  */
    447 nlm_res *
    448 nlm_lock_1_svc(nlm_lockargs *arg, struct svc_req *rqstp)
    449 {
    450 	static nlm_res result;
    451 	struct nlm4_lockargs arg4;
    452 	nlmtonlm4(&arg->alock, &arg4.alock);
    453 	arg4.cookie = arg->cookie;
    454 	arg4.block = arg->block;
    455 	arg4.exclusive = arg->exclusive;
    456 	arg4.reclaim = arg->reclaim;
    457 	arg4.state = arg->state;
    458 
    459 	if (debug_level)
    460 		log_from_addr("nlm_lock", rqstp);
    461 
    462 	/* copy cookie from arg to result.  See comment in nlm_test_1() */
    463 	result.cookie = arg->cookie;
    464 
    465 	result.stat.stat = getlock(&arg4, rqstp, LOCK_MON);
    466 	return &result;
    467 }
    468 
    469 void *
    470 nlm_lock_msg_1_svc(nlm_lockargs *arg, struct svc_req *rqstp)
    471 {
    472 	static nlm_res result;
    473 	struct nlm4_lockargs arg4;
    474 
    475 	nlmtonlm4(&arg->alock, &arg4.alock);
    476 	arg4.cookie = arg->cookie;
    477 	arg4.block = arg->block;
    478 	arg4.exclusive = arg->exclusive;
    479 	arg4.reclaim = arg->reclaim;
    480 	arg4.state = arg->state;
    481 
    482 	if (debug_level)
    483 		log_from_addr("nlm_lock_msg", rqstp);
    484 
    485 	result.cookie = arg->cookie;
    486 	result.stat.stat = getlock(&arg4, rqstp, LOCK_ASYNC | LOCK_MON);
    487 	transmit_result(NLM_LOCK_RES, &result,
    488 	    (struct sockaddr *)svc_getrpccaller(rqstp->rq_xprt)->buf);
    489 
    490 	return NULL;
    491 }
    492 
    493 /* nlm_cancel -------------------------------------------------------------- */
    494 /*
    495  * Purpose:	Cancel a blocked lock request
    496  * Returns:	granted or denied
    497  * Notes:
    498  */
    499 nlm_res *
    500 nlm_cancel_1_svc(nlm_cancargs *arg, struct svc_req *rqstp)
    501 {
    502 	static nlm_res result;
    503 	struct nlm4_lock arg4;
    504 
    505 	nlmtonlm4(&arg->alock, &arg4);
    506 
    507 	if (debug_level)
    508 		log_from_addr("nlm_cancel", rqstp);
    509 
    510 	/* copy cookie from arg to result.  See comment in nlm_test_1() */
    511 	result.cookie = arg->cookie;
    512 
    513 	/*
    514 	 * Since at present we never return 'nlm_blocked', there can never be
    515 	 * a lock to cancel, so this call always fails.
    516 	 */
    517 	result.stat.stat = unlock(&arg4, LOCK_CANCEL);
    518 	return &result;
    519 }
    520 
    521 void *
    522 nlm_cancel_msg_1_svc(nlm_cancargs *arg, struct svc_req *rqstp)
    523 {
    524 	static nlm_res result;
    525 	struct nlm4_lock arg4;
    526 
    527 	nlmtonlm4(&arg->alock, &arg4);
    528 
    529 	if (debug_level)
    530 		log_from_addr("nlm_cancel_msg", rqstp);
    531 
    532 	result.cookie = arg->cookie;
    533 	/*
    534 	 * Since at present we never return 'nlm_blocked', there can never be
    535 	 * a lock to cancel, so this call always fails.
    536 	 */
    537 	result.stat.stat = unlock(&arg4, LOCK_CANCEL);
    538 	transmit_result(NLM_CANCEL_RES, &result,
    539 	    (struct sockaddr *)svc_getrpccaller(rqstp->rq_xprt)->buf);
    540 	return NULL;
    541 }
    542 
    543 /* nlm_unlock -------------------------------------------------------------- */
    544 /*
    545  * Purpose:	Release an existing lock
    546  * Returns:	Always granted, unless during grace period
    547  * Notes:	"no such lock" error condition is ignored, as the
    548  *		protocol uses unreliable UDP datagrams, and may well
    549  *		re-try an unlock that has already succeeded.
    550  */
    551 nlm_res *
    552 nlm_unlock_1_svc(nlm_unlockargs *arg, struct svc_req *rqstp)
    553 {
    554 	static nlm_res result;
    555 	struct nlm4_lock arg4;
    556 
    557 	nlmtonlm4(&arg->alock, &arg4);
    558 
    559 	if (debug_level)
    560 		log_from_addr("nlm_unlock", rqstp);
    561 
    562 	result.stat.stat = unlock(&arg4, 0);
    563 	result.cookie = arg->cookie;
    564 
    565 	return &result;
    566 }
    567 
    568 void *
    569 nlm_unlock_msg_1_svc(nlm_unlockargs *arg, struct svc_req *rqstp)
    570 {
    571 	static nlm_res result;
    572 	struct nlm4_lock arg4;
    573 
    574 	nlmtonlm4(&arg->alock, &arg4);
    575 
    576 	if (debug_level)
    577 		log_from_addr("nlm_unlock_msg", rqstp);
    578 
    579 	result.stat.stat = unlock(&arg4, 0);
    580 	result.cookie = arg->cookie;
    581 
    582 	transmit_result(NLM_UNLOCK_RES, &result,
    583 	    (struct sockaddr *)svc_getrpccaller(rqstp->rq_xprt)->buf);
    584 	return NULL;
    585 }
    586 
    587 /* ------------------------------------------------------------------------- */
    588 /*
    589  * Client-side pseudo-RPCs for results.  Note that for the client there
    590  * are only nlm_xxx_msg() versions of each call, since the 'real RPC'
    591  * version returns the results in the RPC result, and so the client
    592  * does not normally receive incoming RPCs.
    593  *
    594  * The exception to this is nlm_granted(), which is genuinely an RPC
    595  * call from the server to the client - a 'call-back' in normal procedure
    596  * call terms.
    597  */
    598 
    599 /* nlm_granted ------------------------------------------------------------- */
    600 /*
    601  * Purpose:	Receive notification that formerly blocked lock now granted
    602  * Returns:	always success ('granted')
    603  * Notes:
    604  */
    605 nlm_res *
    606 nlm_granted_1_svc(nlm_testargs *arg, struct svc_req *rqstp)
    607 {
    608 	static nlm_res result;
    609 
    610 	if (debug_level)
    611 		log_from_addr("nlm_granted", rqstp);
    612 
    613 	/* copy cookie from arg to result.  See comment in nlm_test_1() */
    614 	result.cookie = arg->cookie;
    615 
    616 	result.stat.stat = nlm_granted;
    617 	return &result;
    618 }
    619 
    620 void *
    621 nlm_granted_msg_1_svc(nlm_testargs *arg, struct svc_req *rqstp)
    622 {
    623 	static nlm_res result;
    624 
    625 	if (debug_level)
    626 		log_from_addr("nlm_granted_msg", rqstp);
    627 
    628 	result.cookie = arg->cookie;
    629 	result.stat.stat = nlm_granted;
    630 	transmit_result(NLM_GRANTED_RES, &result,
    631 	    (struct sockaddr *)svc_getrpccaller(rqstp->rq_xprt)->buf);
    632 	return NULL;
    633 }
    634 
    635 /* nlm_test_res ------------------------------------------------------------ */
    636 /*
    637  * Purpose:	Accept result from earlier nlm_test_msg() call
    638  * Returns:	Nothing
    639  */
    640 void *
    641 /*ARGSUSED*/
    642 nlm_test_res_1_svc(nlm_testres *arg, struct svc_req *rqstp)
    643 {
    644 	if (debug_level)
    645 		log_from_addr("nlm_test_res", rqstp);
    646 	return NULL;
    647 }
    648 
    649 /* nlm_lock_res ------------------------------------------------------------ */
    650 /*
    651  * Purpose:	Accept result from earlier nlm_lock_msg() call
    652  * Returns:	Nothing
    653  */
    654 void *
    655 /*ARGSUSED*/
    656 nlm_lock_res_1_svc(nlm_res *arg, struct svc_req *rqstp)
    657 {
    658 	if (debug_level)
    659 		log_from_addr("nlm_lock_res", rqstp);
    660 
    661 	return NULL;
    662 }
    663 
    664 /* nlm_cancel_res ---------------------------------------------------------- */
    665 /*
    666  * Purpose:	Accept result from earlier nlm_cancel_msg() call
    667  * Returns:	Nothing
    668  */
    669 void *
    670 /*ARGSUSED*/
    671 nlm_cancel_res_1_svc(nlm_res *arg, struct svc_req *rqstp)
    672 {
    673 	if (debug_level)
    674 		log_from_addr("nlm_cancel_res", rqstp);
    675 	return NULL;
    676 }
    677 
    678 /* nlm_unlock_res ---------------------------------------------------------- */
    679 /*
    680  * Purpose:	Accept result from earlier nlm_unlock_msg() call
    681  * Returns:	Nothing
    682  */
    683 void *
    684 /*ARGSUSED*/
    685 nlm_unlock_res_1_svc(nlm_res *arg, struct svc_req *rqstp)
    686 {
    687 	if (debug_level)
    688 		log_from_addr("nlm_unlock_res", rqstp);
    689 	return NULL;
    690 }
    691 
    692 /* nlm_granted_res --------------------------------------------------------- */
    693 /*
    694  * Purpose:	Accept result from earlier nlm_granted_msg() call
    695  * Returns:	Nothing
    696  */
    697 void *
    698 /*ARGSUSED*/
    699 nlm_granted_res_1_svc(nlm_res *arg, struct svc_req *rqstp)
    700 {
    701 	if (debug_level)
    702 		log_from_addr("nlm_granted_res", rqstp);
    703 	return NULL;
    704 }
    705 
    706 /* ------------------------------------------------------------------------- */
    707 /*
    708  * Calls for PCNFS locking (aka non-monitored locking, no involvement
    709  * of rpc.statd).
    710  *
    711  * These are all genuine RPCs - no nlm_xxx_msg() nonsense here.
    712  */
    713 
    714 /* nlm_share --------------------------------------------------------------- */
    715 /*
    716  * Purpose:	Establish a DOS-style lock
    717  * Returns:	success or failure
    718  * Notes:	Blocking locks are not supported - client is expected
    719  *		to retry if required.
    720  */
    721 nlm_shareres *
    722 nlm_share_3_svc(nlm_shareargs *arg, struct svc_req *rqstp)
    723 {
    724 	static nlm_shareres result;
    725 
    726 	if (debug_level)
    727 		log_from_addr("nlm_share", rqstp);
    728 
    729 	result.cookie = arg->cookie;
    730 	result.stat = nlm_granted;
    731 	result.sequence = 1234356;	/* X/Open says this field is ignored? */
    732 	return &result;
    733 }
    734 
    735 /* nlm_unshare ------------------------------------------------------------ */
    736 /*
    737  * Purpose:	Release a DOS-style lock
    738  * Returns:	nlm_granted, unless in grace period
    739  * Notes:
    740  */
    741 nlm_shareres *
    742 nlm_unshare_3_svc(nlm_shareargs *arg, struct svc_req *rqstp)
    743 {
    744 	static nlm_shareres result;
    745 
    746 	if (debug_level)
    747 		log_from_addr("nlm_unshare", rqstp);
    748 
    749 	result.cookie = arg->cookie;
    750 	result.stat = nlm_granted;
    751 	result.sequence = 1234356;	/* X/Open says this field is ignored? */
    752 	return &result;
    753 }
    754 
    755 /* nlm_nm_lock ------------------------------------------------------------ */
    756 /*
    757  * Purpose:	non-monitored version of nlm_lock()
    758  * Returns:	as for nlm_lock()
    759  * Notes:	These locks are in the same style as the standard nlm_lock,
    760  *		but the rpc.statd should not be called to establish a
    761  *		monitor for the client machine, since that machine is
    762  *		declared not to be running a rpc.statd, and so would not
    763  *		respond to the statd protocol.
    764  */
    765 nlm_res *
    766 nlm_nm_lock_3_svc(nlm_lockargs *arg, struct svc_req *rqstp)
    767 {
    768 	static nlm_res result;
    769 
    770 	if (debug_level)
    771 		log_from_addr("nlm_nm_lock", rqstp);
    772 
    773 	/* copy cookie from arg to result.  See comment in nlm_test_1() */
    774 	result.cookie = arg->cookie;
    775 	result.stat.stat = nlm_granted;
    776 	return &result;
    777 }
    778 
    779 /* nlm_free_all ------------------------------------------------------------ */
    780 /*
    781  * Purpose:	Release all locks held by a named client
    782  * Returns:	Nothing
    783  * Notes:	Potential denial of service security problem here - the
    784  *		locks to be released are specified by a host name, independent
    785  *		of the address from which the request has arrived.
    786  *		Should probably be rejected if the named host has been
    787  *		using monitored locks.
    788  */
    789 void *
    790 /*ARGSUSED*/
    791 nlm_free_all_3_svc(nlm_notify *arg, struct svc_req *rqstp)
    792 {
    793 	static char dummy;
    794 
    795 	if (debug_level)
    796 		log_from_addr("nlm_free_all", rqstp);
    797 	return &dummy;
    798 }
    799 
    800 /* calls for nlm version 4 (NFSv3) */
    801 /* nlm_test ---------------------------------------------------------------- */
    802 /*
    803  * Purpose:	Test whether a specified lock would be granted if requested
    804  * Returns:	nlm_granted (or error code)
    805  * Notes:
    806  */
    807 nlm4_testres *
    808 nlm4_test_4_svc(nlm4_testargs *arg, struct svc_req *rqstp)
    809 {
    810 	static nlm4_testres result;
    811 	struct nlm4_holder *holder;
    812 
    813 	if (debug_level)
    814 		log_from_addr("nlm4_test", rqstp);
    815 
    816 	holder = testlock(&arg->alock, LOCK_V4);
    817 
    818 	/*
    819 	 * Copy the cookie from the argument into the result.  Note that this
    820 	 * is slightly hazardous, as the structure contains a pointer to a
    821 	 * malloc()ed buffer that will get freed by the caller.  However, the
    822 	 * main function transmits the result before freeing the argument
    823 	 * so it is in fact safe.
    824 	 */
    825 	result.cookie = arg->cookie;
    826 	if (holder == NULL) {
    827 		result.stat.stat = nlm4_granted;
    828 	} else {
    829 		result.stat.stat = nlm4_denied;
    830 		(void)memcpy(&result.stat.nlm4_testrply_u.holder, holder,
    831 		    sizeof(struct nlm4_holder));
    832 	}
    833 	return &result;
    834 }
    835 
    836 void *
    837 nlm4_test_msg_4_svc(nlm4_testargs *arg, struct svc_req *rqstp)
    838 {
    839 	nlm4_testres result;
    840 	static char dummy;
    841 	struct sockaddr *addr;
    842 	CLIENT *cli;
    843 	int success;
    844 	struct timeval timeo;
    845 	struct nlm4_holder *holder;
    846 
    847 	if (debug_level)
    848 		log_from_addr("nlm4_test_msg", rqstp);
    849 
    850 	holder = testlock(&arg->alock, LOCK_V4);
    851 
    852 	result.cookie = arg->cookie;
    853 	if (holder == NULL) {
    854 		result.stat.stat = nlm4_granted;
    855 	} else {
    856 		result.stat.stat = nlm4_denied;
    857 		(void)memcpy(&result.stat.nlm4_testrply_u.holder, holder,
    858 		    sizeof(struct nlm4_holder));
    859 	}
    860 
    861 	/*
    862 	 * nlm_test has different result type to the other operations, so
    863 	 * can't use transmit4_result() in this case
    864 	 */
    865 	addr = svc_getrpccaller(rqstp->rq_xprt)->buf;
    866 	if ((cli = get_client(addr, NLM_VERS4)) != NULL) {
    867 		timeo.tv_sec = 0; /* No timeout - not expecting response */
    868 		timeo.tv_usec = 0;
    869 
    870 		success = clnt_call(cli, NLM4_TEST_RES, xdr_nlm4_testres,
    871 		    &result, xdr_void, &dummy, timeo);
    872 
    873 		if (debug_level > 2)
    874 			syslog(LOG_DEBUG, "clnt_call returns %d", success);
    875 	}
    876 	return NULL;
    877 }
    878 
    879 /* nlm_lock ---------------------------------------------------------------- */
    880 /*
    881  * Purposes:	Establish a lock
    882  * Returns:	granted, denied or blocked
    883  * Notes:	*** grace period support missing
    884  */
    885 nlm4_res *
    886 nlm4_lock_4_svc(nlm4_lockargs *arg, struct svc_req *rqstp)
    887 {
    888 	static nlm4_res result;
    889 
    890 	if (debug_level)
    891 		log_from_addr("nlm4_lock", rqstp);
    892 
    893 	/* copy cookie from arg to result.  See comment in nlm_test_4() */
    894 	result.cookie = arg->cookie;
    895 
    896 	result.stat.stat = (enum nlm4_stats)getlock(arg, rqstp,
    897 	    LOCK_MON | LOCK_V4);
    898 	return &result;
    899 }
    900 
    901 void *
    902 nlm4_lock_msg_4_svc(nlm4_lockargs *arg, struct svc_req *rqstp)
    903 {
    904 	static nlm4_res result;
    905 
    906 	if (debug_level)
    907 		log_from_addr("nlm4_lock_msg", rqstp);
    908 
    909 	result.cookie = arg->cookie;
    910 	result.stat.stat = (enum nlm4_stats)getlock(arg, rqstp,
    911 	    LOCK_MON | LOCK_ASYNC | LOCK_V4);
    912 	transmit4_result(NLM4_LOCK_RES, &result,
    913 	    (struct sockaddr *)svc_getrpccaller(rqstp->rq_xprt)->buf);
    914 
    915 	return NULL;
    916 }
    917 
    918 /* nlm_cancel -------------------------------------------------------------- */
    919 /*
    920  * Purpose:	Cancel a blocked lock request
    921  * Returns:	granted or denied
    922  * Notes:
    923  */
    924 nlm4_res *
    925 nlm4_cancel_4_svc(nlm4_cancargs *arg, struct svc_req *rqstp)
    926 {
    927 	static nlm4_res result;
    928 
    929 	if (debug_level)
    930 		log_from_addr("nlm4_cancel", rqstp);
    931 
    932 	/* copy cookie from arg to result.  See comment in nlm_test_1() */
    933 	result.cookie = arg->cookie;
    934 
    935 	/*
    936 	 * Since at present we never return 'nlm_blocked', there can never be
    937 	 * a lock to cancel, so this call always fails.
    938 	 */
    939 	result.stat.stat = (enum nlm4_stats)unlock(&arg->alock, LOCK_CANCEL);
    940 	return &result;
    941 }
    942 
    943 void *
    944 nlm4_cancel_msg_4_svc(nlm4_cancargs *arg, struct svc_req *rqstp)
    945 {
    946 	static nlm4_res result;
    947 
    948 	if (debug_level)
    949 		log_from_addr("nlm4_cancel_msg", rqstp);
    950 
    951 	result.cookie = arg->cookie;
    952 	/*
    953 	 * Since at present we never return 'nlm_blocked', there can never be
    954 	 * a lock to cancel, so this call always fails.
    955 	 */
    956 	result.stat.stat = (enum nlm4_stats)unlock(&arg->alock,
    957 	    LOCK_CANCEL | LOCK_V4);
    958 	transmit4_result(NLM4_CANCEL_RES, &result,
    959 	    (struct sockaddr *)svc_getrpccaller(rqstp->rq_xprt)->buf);
    960 	return NULL;
    961 }
    962 
    963 /* nlm_unlock -------------------------------------------------------------- */
    964 /*
    965  * Purpose:	Release an existing lock
    966  * Returns:	Always granted, unless during grace period
    967  * Notes:	"no such lock" error condition is ignored, as the
    968  *		protocol uses unreliable UDP datagrams, and may well
    969  *		re-try an unlock that has already succeeded.
    970  */
    971 nlm4_res *
    972 nlm4_unlock_4_svc(nlm4_unlockargs *arg, struct svc_req *rqstp)
    973 {
    974 	static nlm4_res result;
    975 
    976 	if (debug_level)
    977 		log_from_addr("nlm4_unlock", rqstp);
    978 
    979 	result.stat.stat = (enum nlm4_stats)unlock(&arg->alock, LOCK_V4);
    980 	result.cookie = arg->cookie;
    981 
    982 	return &result;
    983 }
    984 
    985 void *
    986 nlm4_unlock_msg_4_svc(nlm4_unlockargs *arg, struct svc_req *rqstp)
    987 {
    988 	static nlm4_res result;
    989 
    990 	if (debug_level)
    991 		log_from_addr("nlm4_unlock_msg", rqstp);
    992 
    993 	result.stat.stat = (enum nlm4_stats)unlock(&arg->alock, LOCK_V4);
    994 	result.cookie = arg->cookie;
    995 
    996 	transmit4_result(NLM4_UNLOCK_RES, &result,
    997 	    (struct sockaddr *)svc_getrpccaller(rqstp->rq_xprt)->buf);
    998 	return NULL;
    999 }
   1000 
   1001 /* ------------------------------------------------------------------------- */
   1002 /*
   1003  * Client-side pseudo-RPCs for results.  Note that for the client there
   1004  * are only nlm_xxx_msg() versions of each call, since the 'real RPC'
   1005  * version returns the results in the RPC result, and so the client
   1006  * does not normally receive incoming RPCs.
   1007  *
   1008  * The exception to this is nlm_granted(), which is genuinely an RPC
   1009  * call from the server to the client - a 'call-back' in normal procedure
   1010  * call terms.
   1011  */
   1012 
   1013 /* nlm_granted ------------------------------------------------------------- */
   1014 /*
   1015  * Purpose:	Receive notification that formerly blocked lock now granted
   1016  * Returns:	always success ('granted')
   1017  * Notes:
   1018  */
   1019 nlm4_res *
   1020 nlm4_granted_4_svc(nlm4_testargs *arg, struct svc_req *rqstp)
   1021 {
   1022 	static nlm4_res result;
   1023 
   1024 	if (debug_level)
   1025 		log_from_addr("nlm4_granted", rqstp);
   1026 
   1027 	/* copy cookie from arg to result.  See comment in nlm_test_1() */
   1028 	result.cookie = arg->cookie;
   1029 
   1030 	result.stat.stat = nlm4_granted;
   1031 	return &result;
   1032 }
   1033 
   1034 void *
   1035 nlm4_granted_msg_4_svc(nlm4_testargs *arg, struct svc_req *rqstp)
   1036 {
   1037 	static nlm4_res result;
   1038 
   1039 	if (debug_level)
   1040 		log_from_addr("nlm4_granted_msg", rqstp);
   1041 
   1042 	result.cookie = arg->cookie;
   1043 	result.stat.stat = nlm4_granted;
   1044 	transmit4_result(NLM4_GRANTED_RES, &result,
   1045 	    (struct sockaddr *)svc_getrpccaller(rqstp->rq_xprt)->buf);
   1046 	return NULL;
   1047 }
   1048 
   1049 /* nlm_test_res ------------------------------------------------------------ */
   1050 /*
   1051  * Purpose:	Accept result from earlier nlm_test_msg() call
   1052  * Returns:	Nothing
   1053  */
   1054 void *
   1055 /*ARGSUSED*/
   1056 nlm4_test_res_4_svc(nlm4_testres *arg, struct svc_req *rqstp)
   1057 {
   1058 	if (debug_level)
   1059 		log_from_addr("nlm4_test_res", rqstp);
   1060 	return NULL;
   1061 }
   1062 
   1063 /* nlm_lock_res ------------------------------------------------------------ */
   1064 /*
   1065  * Purpose:	Accept result from earlier nlm_lock_msg() call
   1066  * Returns:	Nothing
   1067  */
   1068 void *
   1069 /*ARGSUSED*/
   1070 nlm4_lock_res_4_svc(nlm4_res *arg, struct svc_req *rqstp)
   1071 {
   1072 	if (debug_level)
   1073 		log_from_addr("nlm4_lock_res", rqstp);
   1074 
   1075 	return NULL;
   1076 }
   1077 
   1078 /* nlm_cancel_res ---------------------------------------------------------- */
   1079 /*
   1080  * Purpose:	Accept result from earlier nlm_cancel_msg() call
   1081  * Returns:	Nothing
   1082  */
   1083 void *
   1084 /*ARGSUSED*/
   1085 nlm4_cancel_res_4_svc(nlm4_res *arg, struct svc_req *rqstp)
   1086 {
   1087 	if (debug_level)
   1088 		log_from_addr("nlm4_cancel_res", rqstp);
   1089 	return NULL;
   1090 }
   1091 
   1092 /* nlm_unlock_res ---------------------------------------------------------- */
   1093 /*
   1094  * Purpose:	Accept result from earlier nlm_unlock_msg() call
   1095  * Returns:	Nothing
   1096  */
   1097 void *
   1098 /*ARGSUSED*/
   1099 nlm4_unlock_res_4_svc(nlm4_res *arg, struct svc_req *rqstp)
   1100 {
   1101 	if (debug_level)
   1102 		log_from_addr("nlm4_unlock_res", rqstp);
   1103 	return NULL;
   1104 }
   1105 
   1106 /* nlm_granted_res --------------------------------------------------------- */
   1107 /*
   1108  * Purpose:	Accept result from earlier nlm_granted_msg() call
   1109  * Returns:	Nothing
   1110  */
   1111 void *
   1112 /*ARGSUSED*/
   1113 nlm4_granted_res_4_svc(nlm4_res *arg, struct svc_req *rqstp)
   1114 {
   1115 	if (debug_level)
   1116 		log_from_addr("nlm4_granted_res", rqstp);
   1117 	return NULL;
   1118 }
   1119 
   1120 /* ------------------------------------------------------------------------- */
   1121 /*
   1122  * Calls for PCNFS locking (aka non-monitored locking, no involvement
   1123  * of rpc.statd).
   1124  *
   1125  * These are all genuine RPCs - no nlm_xxx_msg() nonsense here.
   1126  */
   1127 
   1128 /* nlm_share --------------------------------------------------------------- */
   1129 /*
   1130  * Purpose:	Establish a DOS-style lock
   1131  * Returns:	success or failure
   1132  * Notes:	Blocking locks are not supported - client is expected
   1133  *		to retry if required.
   1134  */
   1135 nlm4_shareres *
   1136 nlm4_share_4_svc(nlm4_shareargs *arg, struct svc_req *rqstp)
   1137 {
   1138 	static nlm4_shareres result;
   1139 
   1140 	if (debug_level)
   1141 		log_from_addr("nlm4_share", rqstp);
   1142 
   1143 	result.cookie = arg->cookie;
   1144 	result.stat = nlm4_granted;
   1145 	result.sequence = 1234356;	/* X/Open says this field is ignored? */
   1146 	return &result;
   1147 }
   1148 
   1149 /* nlm4_unshare ------------------------------------------------------------ */
   1150 /*
   1151  * Purpose:	Release a DOS-style lock
   1152  * Returns:	nlm_granted, unless in grace period
   1153  * Notes:
   1154  */
   1155 nlm4_shareres *
   1156 nlm4_unshare_4_svc(nlm4_shareargs *arg, struct svc_req *rqstp)
   1157 {
   1158 	static nlm4_shareres result;
   1159 
   1160 	if (debug_level)
   1161 		log_from_addr("nlm_unshare", rqstp);
   1162 
   1163 	result.cookie = arg->cookie;
   1164 	result.stat = nlm4_granted;
   1165 	result.sequence = 1234356;	/* X/Open says this field is ignored? */
   1166 	return &result;
   1167 }
   1168 
   1169 /* nlm4_nm_lock ------------------------------------------------------------ */
   1170 /*
   1171  * Purpose:	non-monitored version of nlm4_lock()
   1172  * Returns:	as for nlm4_lock()
   1173  * Notes:	These locks are in the same style as the standard nlm4_lock,
   1174  *		but the rpc.statd should not be called to establish a
   1175  *		monitor for the client machine, since that machine is
   1176  *		declared not to be running a rpc.statd, and so would not
   1177  *		respond to the statd protocol.
   1178  */
   1179 nlm4_res *
   1180 nlm4_nm_lock_4_svc(nlm4_lockargs *arg, struct svc_req *rqstp)
   1181 {
   1182 	static nlm4_res result;
   1183 
   1184 	if (debug_level)
   1185 		log_from_addr("nlm4_nm_lock", rqstp);
   1186 
   1187 	/* copy cookie from arg to result.  See comment in nlm4_test_1() */
   1188 	result.cookie = arg->cookie;
   1189 	result.stat.stat = nlm4_granted;
   1190 	return &result;
   1191 }
   1192 
   1193 /* nlm4_free_all ------------------------------------------------------------ */
   1194 /*
   1195  * Purpose:	Release all locks held by a named client
   1196  * Returns:	Nothing
   1197  * Notes:	Potential denial of service security problem here - the
   1198  *		locks to be released are specified by a host name, independent
   1199  *		of the address from which the request has arrived.
   1200  *		Should probably be rejected if the named host has been
   1201  *		using monitored locks.
   1202  */
   1203 void *
   1204 /*ARGSUSED*/
   1205 nlm4_free_all_4_svc(nlm_notify *arg, struct svc_req *rqstp)
   1206 {
   1207 	static char dummy;
   1208 
   1209 	if (debug_level)
   1210 		log_from_addr("nlm4_free_all", rqstp);
   1211 	return &dummy;
   1212 }
   1213 
   1214 /* nlm_sm_notify --------------------------------------------------------- */
   1215 /*
   1216  * Purpose:	called by rpc.statd when a monitored host state changes.
   1217  * Returns:	Nothing
   1218  */
   1219 void *
   1220 /*ARGSUSED*/
   1221 nlm_sm_notify_0_svc(struct nlm_sm_status *arg, struct svc_req *rqstp)
   1222 {
   1223 	static char dummy;
   1224 	notify(arg->mon_name, arg->state);
   1225 	return &dummy;
   1226 }
   1227