2 * nsm_client.c -- synthetic client and lockd simulator for testing statd
4 * Copyright (C) 2010 Red Hat, Jeff Layton <jlayton@redhat.com>
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version 2
9 * of the License, or (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor,
19 * Boston, MA 02110-1301, USA.
21 * Very loosely based on "simulator.c" in the statd directory. Original
22 * copyright for that program follows:
24 * Copyright (C) 1995-1997, 1999 Jeffrey A. Uphoff
37 #include <rpc/pmap_clnt.h>
39 #include <sys/socket.h>
40 #include <sys/types.h>
47 #include "nlm_sm_inter.h"
51 static void daemon_simulator(void);
52 static void sim_killer(int sig);
53 static int nsm_client_crash(char *);
54 static int nsm_client_mon(char *, char *, char *, char *, int, int);
55 static int nsm_client_stat(char *, char *);
56 static int nsm_client_notify(char *, char *, char *);
57 static int nsm_client_unmon(char *, char *, char *, int, int);
58 static int nsm_client_unmon_all(char *, char *, int, int);
60 extern void nlm_sm_prog_4(struct svc_req *rqstp, register SVCXPRT *transp);
61 extern void svc_exit(void);
64 * default to 15 retransmit interval, which seems to be the default for
65 * UDP clients w/ legacy glibc RPC
67 static struct timeval retrans_interval =
72 static struct option longopts[] =
74 { "help", 0, 0, 'h' },
75 { "host", 0, 0, 'H' },
76 { "name", 1, 0, 'n' },
77 { "program", 1, 0, 'P' },
78 { "version", 1, 0, 'v' },
86 printf("%s [options] <command> [arg]...\n", program);
87 printf("where command is one of these with the specified args:\n");
88 printf("crash\t\t\t\ttell host to simulate crash\n");
89 printf("daemon\t\t\t\t\tstart up lockd daemon simulator\n");
90 printf("notify <mon_name> <state>\tsend a reboot notification to host\n");
91 printf("stat <mon_name>\t\t\tget status of <mon_name> on host\n");
92 printf("unmon_all\t\t\ttell host to unmon everything\n");
93 printf("unmon <mon_name>\t\t\ttell host to unmon <mon_name>\n");
94 printf("mon <mon_name> <cookie>\t\ttell host to monitor <mon_name> with private <cookie>\n");
99 hex2bin(char *dst, size_t dstlen, char *src)
104 for (i = 0; *src && i < dstlen; i++) {
105 if (sscanf(src, "%2x", &tmp) != 1)
118 bin2hex(char *dst, char *src, size_t srclen)
122 for (i = 0; i < srclen; i++)
123 dst += sprintf(dst, "%02x", 0xff & src[i]);
127 main(int argc, char **argv)
131 char my_name[NI_MAXHOST], host[NI_MAXHOST];
132 char cookie[SM_PRIV_SIZE];
133 int my_prog = NLM_SM_PROG;
134 int my_vers = NLM_SM_VERS4;
139 while ((arg = getopt_long(argc, argv, "hHn:P:v:", longopts,
143 strncpy(host, optarg, sizeof(host));
145 strncpy(my_name, optarg, sizeof(my_name));
147 my_prog = atoi(optarg);
149 my_vers = atoi(optarg);
153 remaining_args = argc - optind;
154 if (remaining_args <= 0)
158 gethostname(my_name, sizeof(my_name));
160 strncpy(host, "127.0.0.1", sizeof(host));
162 if (!strcasecmp(argv[optind], "daemon")) {
164 } else if (!strcasecmp(argv[optind], "crash")) {
165 err = nsm_client_crash(host);
166 } else if (!strcasecmp(argv[optind], "stat")) {
167 if (remaining_args < 2)
169 err = nsm_client_stat(host, argv[optind + 2]);
170 } else if (!strcasecmp(argv[optind], "unmon_all")) {
171 err = nsm_client_unmon_all(host, my_name, my_prog, my_vers);
172 } else if (!strcasecmp(argv[optind], "unmon")) {
173 if (remaining_args < 2)
175 err = nsm_client_unmon(host, argv[optind + 1], my_name, my_prog,
177 } else if (!strcasecmp(argv[optind], "notify")) {
178 if (remaining_args < 2)
180 err = nsm_client_notify(host, argv[optind + 1],
182 } else if (!strcasecmp(argv[optind], "mon")) {
183 if (remaining_args < 2)
186 memset(cookie, '\0', SM_PRIV_SIZE);
187 if (!hex2bin(cookie, sizeof(cookie), argv[optind + 2])) {
188 fprintf(stderr, "SYS:%d\n", EINVAL);
189 printf("Unable to convert hex cookie %s to binary.\n",
194 err = nsm_client_mon(host, argv[optind + 1], cookie, my_name,
197 err = usage(argv[0]);
204 nsm_client_get_rpcclient(const char *node)
208 struct addrinfo hints = { .ai_flags = AI_ADDRCONFIG };
210 CLIENT *client = NULL;
213 hints.ai_family = AF_INET;
214 #endif /* IPV6_ENABLED */
216 /* FIXME: allow support for providing port? */
217 err = getaddrinfo(node, NULL, &hints, &ai);
219 fprintf(stderr, "EAI:%d\n", err);
220 if (err == EAI_SYSTEM)
221 fprintf(stderr, "SYS:%d\n", errno);
222 printf("Unable to translate host to address: %s\n",
223 err == EAI_SYSTEM ? strerror(errno) :
228 /* FIXME: allow for TCP too? */
229 port = nfs_getport(ai->ai_addr, ai->ai_addrlen, SM_PROG,
230 SM_VERS, IPPROTO_UDP);
232 fprintf(stderr, "RPC:%d\n", rpc_createerr.cf_stat);
233 printf("Unable to determine port for service\n");
237 nfs_set_port(ai->ai_addr, port);
239 client = nfs_get_rpcclient(ai->ai_addr, ai->ai_addrlen, IPPROTO_UDP,
240 SM_PROG, SM_VERS, &retrans_interval);
242 fprintf(stderr, "RPC:%d\n", rpc_createerr.cf_stat);
243 printf("RPC client creation failed\n");
251 nsm_client_mon(char *calling, char *monitoring, char *cookie, char *my_name,
252 int my_prog, int my_vers)
259 printf("Calling %s (as %s) to monitor %s\n", calling, my_name,
262 if ((client = nsm_client_get_rpcclient(calling)) == NULL)
265 memcpy(mon.priv, cookie, SM_PRIV_SIZE);
266 mon.mon_id.my_id.my_name = my_name;
267 mon.mon_id.my_id.my_prog = my_prog;
268 mon.mon_id.my_id.my_vers = my_vers;
269 mon.mon_id.my_id.my_proc = NLM_SM_NOTIFY;
270 mon.mon_id.mon_name = monitoring;
272 if (!(result = sm_mon_1(&mon, client))) {
273 fprintf(stderr, "RPC:%d\n", rpc_createerr.cf_stat);
274 printf("%s\n", clnt_sperror(client, "sm_mon_1"));
279 printf("SM_MON request %s, state: %d\n",
280 result->res_stat == stat_succ ? "successful" : "failed",
283 if (result->res_stat != stat_succ) {
284 fprintf(stderr, "RPC:%d\n", rpc_createerr.cf_stat);
289 clnt_destroy(client);
294 nsm_client_unmon(char *calling, char *unmonitoring, char *my_name, int my_prog,
302 printf("Calling %s (as %s) to unmonitor %s\n", calling, my_name,
305 if ((client = nsm_client_get_rpcclient(calling)) == NULL)
308 mon_id.my_id.my_name = my_name;
309 mon_id.my_id.my_prog = my_prog;
310 mon_id.my_id.my_vers = my_vers;
311 mon_id.my_id.my_proc = NLM_SM_NOTIFY;
312 mon_id.mon_name = unmonitoring;
314 if (!(result = sm_unmon_1(&mon_id, client))) {
315 fprintf(stderr, "RPC:%d\n", rpc_createerr.cf_stat);
316 printf("%s\n", clnt_sperror(client, "sm_unmon_1"));
321 printf("SM_UNMON state: %d\n", result->state);
324 clnt_destroy(client);
329 nsm_client_unmon_all(char *calling, char *my_name, int my_prog, int my_vers)
336 printf("Calling %s (as %s) to unmonitor all hosts\n", calling, my_name);
338 if ((client = nsm_client_get_rpcclient(calling)) == NULL) {
339 printf("RPC client creation failed\n");
343 my_id.my_name = my_name;
344 my_id.my_prog = my_prog;
345 my_id.my_vers = my_vers;
346 my_id.my_proc = NLM_SM_NOTIFY;
348 if (!(result = sm_unmon_all_1(&my_id, client))) {
349 fprintf(stderr, "RPC:%d\n", rpc_createerr.cf_stat);
350 printf("%s\n", clnt_sperror(client, "sm_unmon_all_1"));
355 printf("SM_UNMON_ALL state: %d\n", result->state);
362 nsm_client_crash(char *host)
366 if ((client = nsm_client_get_rpcclient(host)) == NULL)
369 if (!sm_simu_crash_1(NULL, client)) {
370 fprintf(stderr, "RPC:%d\n", rpc_createerr.cf_stat);
371 printf("%s\n", clnt_sperror(client, "sm_simu_crash_1"));
379 nsm_client_stat(char *calling, char *monitoring)
385 if ((client = nsm_client_get_rpcclient(calling)) == NULL)
388 checking.mon_name = monitoring;
390 if (!(result = sm_stat_1(&checking, client))) {
391 fprintf(stderr, "RPC:%d\n", rpc_createerr.cf_stat);
392 printf("%s\n", clnt_sperror(client, "sm_stat_1"));
396 if (result->res_stat != stat_succ) {
397 fprintf(stderr, "RPC:%d\n", rpc_createerr.cf_stat);
398 printf("stat_fail from %s for %s, state: %d\n", calling,
399 monitoring, result->state);
403 printf("stat_succ from %s for %s, state: %d\n", calling,
404 monitoring, result->state);
410 nsm_client_notify(char *calling, char *mon_name, char *statestr)
414 stat_chge stat_chge = { .mon_name = mon_name };
416 stat_chge.state = atoi(statestr);
418 if ((client = nsm_client_get_rpcclient(calling)) == NULL)
421 if (!sm_notify_1(&stat_chge, client)) {
422 fprintf(stderr, "RPC:%d\n", rpc_createerr.cf_stat);
423 printf("%s\n", clnt_sperror(client, "sm_notify_1"));
430 static void sim_killer(int sig)
433 (void) rpcb_unset(NLM_SM_PROG, NLM_SM_VERS4, NULL);
435 (void) pmap_unset(NLM_SM_PROG, NLM_SM_VERS4);
440 static void daemon_simulator(void)
442 signal(SIGHUP, sim_killer);
443 signal(SIGINT, sim_killer);
444 signal(SIGTERM, sim_killer);
445 /* FIXME: allow for different versions? */
446 nfs_svc_create("nlmsim", NLM_SM_PROG, NLM_SM_VERS4, nlm_sm_prog_4, 0);
450 void *nlm_sm_notify_4_svc(struct nlm_sm_notify *argp, struct svc_req *rqstp)
453 char priv[SM_PRIV_SIZE * 2 + 1];
455 bin2hex(priv, argp->priv, SM_PRIV_SIZE);
457 printf("state=%d:mon_name=%s:private=%s\n", argp->state,
458 argp->mon_name, priv);
459 return (void *) &result;
462 void *nlm_sm_notify_3_svc(struct nlm_sm_notify *argp, struct svc_req *rqstp)
464 return nlm_sm_notify_4_svc(argp, rqstp);