1    	/*
2    	 * Copyright (c) 2006-2020 Red Hat, Inc.
3    	 *
4    	 * All rights reserved.
5    	 *
6    	 * Author: Steven Dake <sdake@redhat.com>
7    	 *
8    	 * This software licensed under BSD license, the text of which follows:
9    	 *
10   	 * Redistribution and use in source and binary forms, with or without
11   	 * modification, are permitted provided that the following conditions are met:
12   	 *
13   	 * - Redistributions of source code must retain the above copyright notice,
14   	 *   this list of conditions and the following disclaimer.
15   	 * - Redistributions in binary form must reproduce the above copyright notice,
16   	 *   this list of conditions and the following disclaimer in the documentation
17   	 *   and/or other materials provided with the distribution.
18   	 * - Neither the name of the MontaVista Software, Inc. nor the names of its
19   	 *   contributors may be used to endorse or promote products derived from this
20   	 *   software without specific prior written permission.
21   	 *
22   	 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
23   	 * AND 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 COPYRIGHT OWNER OR CONTRIBUTORS BE
26   	 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
27   	 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
28   	 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
29   	 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
30   	 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
31   	 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
32   	 * THE POSSIBILITY OF SUCH DAMAGE.
33   	 */
34   	
35   	#include <config.h>
36   	
37   	#include <stdio.h>
38   	#include <stdlib.h>
39   	#include <errno.h>
40   	#include <unistd.h>
41   	#include <string.h>
42   	#include <pthread.h>
43   	#include <sys/types.h>
44   	#include <sys/socket.h>
45   	#include <sys/select.h>
46   	#include <sys/un.h>
47   	#include <netinet/in.h>
48   	#include <arpa/inet.h>
49   	#include <limits.h>
50   	#include <getopt.h>
51   	
52   	#include <corosync/corotypes.h>
53   	#include <corosync/totem/totem.h>
54   	#include <corosync/cfg.h>
55   	#include <corosync/cmap.h>
56   	#include "util.h"
57   	
58   	#define cs_repeat(result, max, code)				\
59   		do {							\
60   			int counter = 0;				\
61   			do {						\
62   				result = code;				\
63   				if (result == CS_ERR_TRY_AGAIN) {	\
64   					sleep(1);			\
65   					counter++;			\
66   				} else {				\
67   					break;				\
68   				}					\
69   			} while (counter < max);			\
70   		} while (0)
71   	
72   	enum user_action {
73   		ACTION_NOOP=0,
74   		ACTION_LINKSTATUS_GET,
75   		ACTION_NODESTATUS_GET,
76   		ACTION_RELOAD_CONFIG,
77   		ACTION_REOPEN_LOG_FILES,
78   		ACTION_SHUTDOW,
79   		ACTION_SHOWADDR,
80   		ACTION_KILL_NODE,
81   	};
82   	
83   	static int node_compare(const void *aptr, const void *bptr)
84   	{
85   		uint32_t a,b;
86   	
87   		a = *(uint32_t *)aptr;
88   		b = *(uint32_t *)bptr;
89   	
90   		return a > b;
91   	}
92   	
93   	static int
94   	nodestatusget_do (enum user_action action, int brief)
95   	{
96   		cs_error_t result;
97   		corosync_cfg_handle_t handle;
98   		cmap_handle_t cmap_handle;
99   		char iter_key[CMAP_KEYNAME_MAXLEN];
100  		cmap_iter_handle_t iter;
101  		unsigned int local_nodeid;
102  		unsigned int local_nodeid_index=0;
103  		unsigned int other_nodeid_index=0;
104  		unsigned int nodeid;
105  		int nodeid_match_guard;
106  		cmap_value_types_t type;
107  		size_t value_len;
108  	#ifdef ENABLE_UDPU
109  		char *str;
110  	#endif
111  		char *transport_str = NULL;
112  		uint32_t nodeid_list[KNET_MAX_HOST];
113  		const char *link_transport[KNET_MAX_LINK];
114  		int s = 0;
115  		int rc = EXIT_SUCCESS;
(1) Event assignment: Assigning: "transport_number" = "TOTEM_TRANSPORT_KNET".
Also see events: [const][dead_error_condition][dead_error_begin]
116  		int transport_number = TOTEM_TRANSPORT_KNET;
117  		int i,j;
118  		struct corosync_cfg_node_status_v1 node_status;
119  	
120  		result = corosync_cfg_initialize (&handle, NULL);
121  		if (result != CS_OK) {
122  			fprintf (stderr, "Could not initialize corosync configuration API error %d\n", result);
123  			exit (EXIT_FAILURE);
124  		}
125  	
126  		result = cmap_initialize (&cmap_handle);
127  		if (result != CS_OK) {
128  			fprintf (stderr, "Could not initialize corosync cmap API error %d\n", result);
129  			exit (EXIT_FAILURE);
130  		}
131  	
132  	#ifdef ENABLE_UDPU
133  		result = cmap_get_string(cmap_handle, "totem.transport", &str);
134  		if (result == CS_OK) {
135  			if (strcmp (str, "udpu") == 0) {
136  				transport_number = TOTEM_TRANSPORT_UDPU;
137  			}
138  			if (strcmp (str, "udp") == 0) {
139  				transport_number = TOTEM_TRANSPORT_UDP;
140  			}
141  			transport_str = str;
142  		}
143  	#endif
144  		if (!transport_str) {
145  			transport_str = strdup("knet"); /* It's the default */
146  		}
147  	
148  		result = corosync_cfg_local_get(handle, &local_nodeid);
149  		if (result != CS_OK) {
150  			fprintf (stderr, "Could not get the local node id, the error is: %d\n", result);
151  			free(transport_str);
152  			cmap_finalize(cmap_handle);
153  			corosync_cfg_finalize(handle);
154  			return EXIT_FAILURE;
155  		}
156  	
157  		/* Get a list of nodes. We do it this way rather than using votequorum as cfgtool
158  		 * needs to be independent of quorum type
159  		 */
160  		result = cmap_iter_init(cmap_handle, "nodelist.node.", &iter);
161  		if (result != CS_OK) {
162  			fprintf (stderr, "Could not get nodelist from cmap. error %d\n", result);
163  			free(transport_str);
164  			cmap_finalize(cmap_handle);
165  			corosync_cfg_finalize(handle);
166  			exit (EXIT_FAILURE);
167  		}
168  	
169  		while ((cmap_iter_next(cmap_handle, iter, iter_key, &value_len, &type)) == CS_OK) {
170  			nodeid_match_guard = 0;
171  			if (sscanf(iter_key, "nodelist.node.%*u.nodeid%n", &nodeid_match_guard) != 0) {
172  				continue;
173  			}
174  			/* check for exact match */
175  			if (nodeid_match_guard != strlen(iter_key)) {
176  				continue;
177  			}
178  			if (cmap_get_uint32(cmap_handle, iter_key, &nodeid) == CS_OK) {
179  				nodeid_list[s++] = nodeid;
180  			}
181  		}
182  	
183  		if (s == 0) {
184  			fprintf(stderr, "No nodes found in nodelist\n");
185  			exit (EXIT_FAILURE);
186  		}
187  	
188  		/* It's nice to have these in nodeid order */
189  		qsort(nodeid_list, s, sizeof(uint32_t), node_compare);
190  	
191  		/*
192  		 * Find local and other nodeid index in nodeid_list
193  		 */
194  		for (i = 0; i < s; i++) {
195  			if (nodeid_list[i] == local_nodeid) {
196  				local_nodeid_index = i;
197  			} else {
198  				/* Bit of an odd one this. but local node only uses one link (of course, to itself)
199  				   so if we want to know which links are active across the cluster we need to look
200  				   at another node (any other) node's link list */
201  				other_nodeid_index = i;
202  			}
203  		}
204  	
205  		/* Get the transport of each link - but set reasonable defaults */
(2) Event const: At condition "transport_number == TOTEM_TRANSPORT_KNET", the value of "transport_number" must be equal to 2.
(3) Event dead_error_condition: The condition "transport_number == TOTEM_TRANSPORT_KNET" must be true.
Also see events: [assignment][dead_error_begin]
206  		if (transport_number == TOTEM_TRANSPORT_KNET) {
207  			for (i = 0; i<KNET_MAX_LINK; i++) {
208  				link_transport[i] = "udp";
209  			}
210  		} else {
CID (unavailable; MK=5d9c95616e4f464f8eb6fdefe27bd39a) (#1 of 2): Logically dead code (DEADCODE):
(4) Event dead_error_begin: Execution cannot reach this statement: "for (i = 0; i < 8; i++) { ...".
Also see events: [assignment][const][dead_error_condition]
211  			for (i = 0; i<KNET_MAX_LINK; i++) {
212  				link_transport[i] = ""; /* No point in displaying "udp" again */
213  			}
214  		}
215  		result = cmap_iter_init(cmap_handle, "totem.interface.", &iter);
216  		if (result == CS_OK) { /* it's fine for this to fail, we just use the defaults */
217  			while ((cmap_iter_next(cmap_handle, iter, iter_key, &value_len, &type)) == CS_OK) {
218  				unsigned int link_number;
219  				char *knet_transport;
220  				char knet_transport_str[CMAP_KEYNAME_MAXLEN];
221  	
222  				/* transport is (sensibly) indexed by link number */
223  				if (sscanf(iter_key, "totem.interface.%u.knet_transport", &link_number) != 1) {
224  					continue;
225  				}
226  				snprintf(knet_transport_str, sizeof(knet_transport_str),
227  					 "totem.interface.%u.knet_transport", link_number);
228  				if (cmap_get_string(cmap_handle, knet_transport_str, &knet_transport) == CS_OK) {
229  					link_transport[link_number] = knet_transport;
230  				}
231  			}
232  	
233  			cmap_iter_finalize(cmap_handle, iter);
234  		}
235  	
236  		cmap_finalize(cmap_handle);
237  	
238  		printf ("Local node ID " CS_PRI_NODE_ID ", transport %s\n", local_nodeid, transport_str);
239  	
240  	        /* If node status requested then do print node-based info */
241  		if (action == ACTION_NODESTATUS_GET) {
242  			for (i=0; i<s; i++) {
243  				result = corosync_cfg_node_status_get(handle, nodeid_list[i], CFG_NODE_STATUS_V1, &node_status);
244  				if (result == CS_OK) {
245  					/* Only display node info if it is reachable (and not us) */
246  					if (node_status.reachable && node_status.nodeid != local_nodeid) {
247  						printf("nodeid: " CS_PRI_NODE_ID "", node_status.nodeid);
248  						printf(" reachable");
249  						if (node_status.remote) {
250  							printf(" remote");
251  						}
252  						if (node_status.external) {
253  							printf(" external");
254  						}
255  	#ifdef HAVE_KNET_ONWIRE_VER
256  						if (transport_number == TOTEM_TRANSPORT_KNET) {
257  							printf("   onwire (min/max/cur): %d, %d, %d",
258  							       node_status.onwire_min,
259  							       node_status.onwire_max,
260  							       node_status.onwire_ver);
261  						}
262  	#endif
263  						printf("\n");
264  						for (j=0; j<CFG_MAX_LINKS; j++) {
265  							if (node_status.link_status[j].enabled) {
266  								printf("   LINK: %d %s", j, link_transport[j]);
267  								printf(" (%s%s%s)",
268  								       node_status.link_status[j].src_ipaddr,
269  								       transport_number==TOTEM_TRANSPORT_KNET?"->":"",
270  								       node_status.link_status[j].dst_ipaddr);
271  								if (node_status.link_status[j].enabled) {
272  									printf(" enabled");
273  								}
274  								if (node_status.link_status[j].connected) {
275  									printf(" connected");
276  								}
277  								if (node_status.link_status[j].dynconnected) {
278  									printf(" dynconnected");
279  								}
280  								printf(" mtu: %d\n", node_status.link_status[j].mtu);
281  							}
282  						}
283  						printf("\n");
284  					}
285  				}
286  			}
287  		}
288  		/* Print in link order */
289  		else {
290  			struct corosync_cfg_node_status_v1 node_info[s];
291  			memset(node_info, 0, sizeof(node_info));
292  	
293  			for (i=0; i<s; i++) {
294  				result = corosync_cfg_node_status_get(handle, nodeid_list[i], CFG_NODE_STATUS_V1, &node_info[i]);
295  				if (result != CS_OK) {
296  					fprintf (stderr, "Could not get the node status for nodeid %d, the error is: %d\n", nodeid_list[i], result);
297  				}
298  			}
299  	
300  			for (i=0; i<CFG_MAX_LINKS; i++) {
301  				if (node_info[other_nodeid_index].link_status[i].enabled) {
302  					printf("LINK ID %d %s\n", i, link_transport[i]);
303  					if (strcmp(link_transport[i], "sctp") == 0) {
304  						printf("**SCTP is deprecated and will be removed in a future release\n");
305  					}
306  					printf("\taddr\t= %s\n", node_info[other_nodeid_index].link_status[i].src_ipaddr);
307  					if (brief) {
308  						printf("\tstatus\t= ");
309  						for (j=0; j<s; j++) {
310  							char status = (node_info[j].link_status[i].enabled |
311  								       (node_info[j].link_status[i].connected << 1)) + '0';
312  							if (j == local_nodeid_index) {
313  								status = 'n';
314  							}
315  							printf("%c", status);
316  						}
317  						printf("\n");
318  					} else {
319  						printf("\tstatus:\n");
320  						for (j=0; j<s; j++) {
321  							printf("\t\tnodeid: " CS_PRI_NODE_ID_PADDED ":\t", node_info[j].nodeid);
322  							if (j == local_nodeid_index) {
323  								printf("localhost");
324  							} else {
325  								if (node_info[j].link_status[i].connected) {
326  									printf("connected");
327  								} else {
328  									printf("disconnected");
329  								}
330  							}
331  							printf("\n");
332  						}
333  					}
334  				}
335  			}
336  		}
337  		free(transport_str);
338  		corosync_cfg_finalize(handle);
339  		return rc;
340  	}
341  	
342  	
343  	static int check_for_reload_errors(void)
344  	{
345  		cmap_handle_t cmap_handle;
346  		cs_error_t result;
347  		char *str;
348  		int res;
349  	
350  		result = cmap_initialize (&cmap_handle);
351  		if (result != CS_OK) {
352  			fprintf (stderr, "Could not initialize corosync cmap API error %d\n", result);
353  			exit (EXIT_FAILURE);
354  		}
355  	
356  		result = cmap_get_string(cmap_handle, "config.reload_error_message", &str);
357  		if (result == CS_OK) {
358  			printf("ERROR from reload: %s - see syslog for more information\n", str);
359  			free(str);
360  			res = 1;
361  		}
362  		else {
363  			res = 0;
364  		}
365  		cmap_finalize(cmap_handle);
366  		return res;
367  	}
368  	
369  	static int reload_config_do (void)
370  	{
371  		cs_error_t result;
372  		corosync_cfg_handle_t handle;
373  		int rc;
374  	
375  		rc = EXIT_SUCCESS;
376  	
377  		printf ("Reloading corosync.conf...\n");
378  		result = corosync_cfg_initialize (&handle, NULL);
379  		if (result != CS_OK) {
380  			fprintf (stderr, "Could not initialize corosync configuration API error %s\n", cs_strerror(result));
381  			exit (EXIT_FAILURE);
382  		}
383  	
384  		result = corosync_cfg_reload_config (handle);
385  		if (result != CS_OK) {
386  			fprintf (stderr, "Could not reload configuration. Error %s\n", cs_strerror(result));
387  			rc = (int)result;
388  		}
389  		else {
390  			printf ("Done\n");
391  		}
392  	
393  		(void)corosync_cfg_finalize (handle);
394  	
395  		if ((rc = check_for_reload_errors())) {
396  			fprintf(stderr, "Errors in applying config, corosync.conf might not match the running system\n");
397  		}
398  	
399  		return (rc);
400  	}
401  	
402  	static int reopen_log_files_do (void)
403  	{
404  		cs_error_t result;
405  		corosync_cfg_handle_t handle;
406  		int rc;
407  	
408  		rc = EXIT_SUCCESS;
409  	
410  		result = corosync_cfg_initialize (&handle, NULL);
411  		if (result != CS_OK) {
412  			fprintf (stderr, "Could not initialize corosync configuration API error %s\n", cs_strerror(result));
413  			exit (EXIT_FAILURE);
414  		}
415  	
416  		result = corosync_cfg_reopen_log_files (handle);
417  		if (result != CS_OK) {
418  			fprintf (stderr, "Could not reopen corosync logging files. Error %s\n", cs_strerror(result));
419  			rc = (int)result;
420  		}
421  	
422  		(void)corosync_cfg_finalize (handle);
423  	
424  		return (rc);
425  	}
426  	
427  	static void shutdown_do(int force)
428  	{
429  		cs_error_t result;
430  		corosync_cfg_handle_t handle;
431  		corosync_cfg_callbacks_t callbacks;
432  		int flag;
433  	
434  		callbacks.corosync_cfg_shutdown_callback = NULL;
435  		if (force) {
436  			flag = COROSYNC_CFG_SHUTDOWN_FLAG_REGARDLESS;
437  		} else {
438  			flag = COROSYNC_CFG_SHUTDOWN_FLAG_REQUEST;
439  		}
440  	
441  		result = corosync_cfg_initialize (&handle, &callbacks);
442  		if (result != CS_OK) {
443  			fprintf (stderr, "Could not initialize corosync configuration API error %d\n", result);
444  			exit (EXIT_FAILURE);
445  		}
446  	
447  		printf ("Shutting down corosync\n");
448  		cs_repeat(result, 30, corosync_cfg_try_shutdown (handle, flag));
449  		if (result != CS_OK) {
450  			fprintf (stderr, "Could not shutdown (error = %d)\n", result);
451  		}
452  	
453  		(void)corosync_cfg_finalize (handle);
454  	}
455  	
456  	static int showaddrs_do(unsigned int nodeid)
457  	{
458  		cs_error_t result;
459  		corosync_cfg_handle_t handle;
460  		int numaddrs;
461  		int i;
462  		int rc = EXIT_SUCCESS;
463  		corosync_cfg_node_address_t addrs[INTERFACE_MAX];
464  	
465  	
466  		result = corosync_cfg_initialize (&handle, NULL);
467  		if (result != CS_OK) {
468  			fprintf (stderr, "Could not initialize corosync configuration API error %d\n", result);
469  			exit (EXIT_FAILURE);
470  		}
471  	
472  		if (corosync_cfg_get_node_addrs(handle, nodeid, INTERFACE_MAX, &numaddrs, addrs) == CS_OK) {
473  			for (i=0; i<numaddrs; i++) {
474  				char buf[INET6_ADDRSTRLEN];
475  				struct sockaddr_storage *ss = (struct sockaddr_storage *)addrs[i].address;
476  				struct sockaddr_in *sin = (struct sockaddr_in *)addrs[i].address;
477  				struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)addrs[i].address;
478  				void *saddr;
479  	
480  				if (!ss->ss_family) {
481  					continue;
482  				}
483  				if (ss->ss_family == AF_INET6) {
484  					saddr = &sin6->sin6_addr;
485  				} else {
486  					saddr = &sin->sin_addr;
487  				}
488  	
489  				inet_ntop(ss->ss_family, saddr, buf, sizeof(buf));
490  				if (i != 0) {
491  					printf(" ");
492  				}
493  				printf("%s", buf);
494  			}
495  			printf("\n");
496  		} else {
497  			fprintf (stderr, "Could not get node address for nodeid %d\n", nodeid);
498  			rc = EXIT_FAILURE;
499  		}
500  	
501  	
502  		(void)corosync_cfg_finalize (handle);
503  		return rc;
504  	}
505  	
506  	
507  	static void killnode_do(unsigned int nodeid)
508  	{
509  		cs_error_t result;
510  		corosync_cfg_handle_t handle;
511  	
512  		printf ("Killing node " CS_PRI_NODE_ID "\n", nodeid);
513  		result = corosync_cfg_initialize (&handle, NULL);
514  		if (result != CS_OK) {
515  			fprintf (stderr, "Could not initialize corosync configuration API error %d\n", result);
516  			exit (EXIT_FAILURE);
517  		}
518  		result = corosync_cfg_kill_node (handle, nodeid, "Killed by corosync-cfgtool");
519  		if (result != CS_OK) {
520  			fprintf (stderr, "Could not kill node (error = %s)\n", cs_strerror(result));
521  			exit(EXIT_FAILURE);
522  		}
523  		(void)corosync_cfg_finalize (handle);
524  	}
525  	
526  	
527  	static void usage_do (void)
528  	{
529  		printf ("corosync-cfgtool [[-i <interface ip>] [-b] -s] [-R] [-L] [-k nodeid] [-a nodeid] [-h] [-H]\n\n");
530  		printf ("A tool for displaying and configuring active parameters within corosync.\n");
531  		printf ("options:\n");
532  		printf ("\t-i\tFinds only information about the specified interface IP address or link id when used with -s..\n");
533  		printf ("\t-s\tDisplays the status of the current links on this node.\n");
534  		printf ("\t-n\tDisplays the status of the connected nodes and their links.\n");
535  		printf ("\t-b\tDisplays the brief status of the current links on this node when used with -s.\n");
536  		printf ("\t-R\tTell all instances of corosync in this cluster to reload corosync.conf.\n");
537  		printf ("\t-L\tTell corosync to reopen all logging files.\n");
538  		printf ("\t-k\tKill a node identified by node id.\n");
539  		printf ("\t-a\tDisplay the IP address(es) of a node\n");
540  		printf ("\t-h\tPrint basic usage.\n");
541  		printf ("\t-H\tShutdown corosync cleanly on this node.\n");
542  		printf ("\t\t--force will shut down corosync regardless of daemon vetos\n");
543  	}
544  	
545  	int main (int argc, char *argv[]) {
546  		int opt;
547  		unsigned int nodeid = 0;
548  		char interface_name[128] = "";
549  		int rc = EXIT_SUCCESS;
550  		enum user_action action = ACTION_NOOP;
551  		int brief = 0;
552  		long long int l;
553  		int option_index = 0;
554  		int force_shutdown  = 0;
555  		const char *options = "i:snbrRLk:a:hH";
556  		struct option long_options[] = {
557  			{"if",       required_argument, 0, 'i'},
558  			{"status",   no_argument,       0, 's'},
559  			{"nodes",    no_argument,       0, 'n'},
560  			{"brief",    no_argument,       0, 'b'},
561  			{"reload",   no_argument,       0, 'R'},
562  			{"reopen",   no_argument,       0, 'L'},
563  			{"kill",     required_argument, 0, 'k'},
564  			{"address",  required_argument, 0, 'a'},
565  			{"shutdown", no_argument,       0, 'H'},
566  			{"force",    no_argument,       0, 0},
567  			{0,          0,                 0, 0}
568  		};
569  	
570  			while ( (opt = getopt_long(argc, argv, options, long_options, &option_index)) != -1 ) {
571  			switch (opt) {
572  				case 0: // options with no short equivalent - just --force ATM
573  				if (strcmp(long_options[option_index].name, "force") == 0) {
574  					force_shutdown = 1;
575  				}
576  				break;
577  			case 'i':
578  				strncpy(interface_name, optarg, sizeof(interface_name));
579  				interface_name[sizeof(interface_name) - 1] = '\0';
580  				break;
581  			case 's':
582  				action = ACTION_LINKSTATUS_GET;
583  				break;
584  			case 'n':
585  				action = ACTION_NODESTATUS_GET;
586  				break;
587  			case 'b':
588  				brief = 1;
589  				break;
590  			case 'R':
591  				action = ACTION_RELOAD_CONFIG;
592  				break;
593  			case 'L':
594  				action = ACTION_REOPEN_LOG_FILES;
595  				break;
596  			case 'k':
597  				if (util_strtonum(optarg, 1, UINT_MAX, &l) == -1) {
598  					fprintf(stderr, "The nodeid was not valid, try a positive number\n");
599  					exit(EXIT_FAILURE);
600  				}
601  				nodeid = l;
602  				action = ACTION_KILL_NODE;
603  				break;
604  			case 'H':
605  				action = ACTION_SHUTDOW;
606  				break;
607  			case 'a':
608  				if (util_strtonum(optarg, 1, UINT_MAX, &l) == -1) {
609  					fprintf(stderr, "The nodeid was not valid, try a positive number\n");
610  					exit(EXIT_FAILURE);
611  				}
612  				nodeid = l;
613  				action = ACTION_SHOWADDR;
614  				break;
615  			case '?':
616  				return (EXIT_FAILURE);
617  				break;
618  			case 'h':
619  			default:
620  				break;
621  			}
622  		}
623  		switch(action) {
624  		case ACTION_LINKSTATUS_GET:
625  			rc = nodestatusget_do(action, brief);
626  			break;
627  		case ACTION_NODESTATUS_GET:
628  			rc = nodestatusget_do(action, brief);
629  			break;
630  		case ACTION_RELOAD_CONFIG:
631  			rc = reload_config_do();
632  			break;
633  		case ACTION_REOPEN_LOG_FILES:
634  			rc = reopen_log_files_do();
635  			break;
636  		case ACTION_KILL_NODE:
637  			killnode_do(nodeid);
638  			break;
639  		case ACTION_SHUTDOW:
640  			shutdown_do(force_shutdown);
641  			break;
642  		case ACTION_SHOWADDR:
643  			rc = showaddrs_do(nodeid);
644  			break;
645  		case ACTION_NOOP:
646  		default:
647  			usage_do();
648  			break;
649  		}
650  	
651  		return (rc);
652  	}
653