xref: /titanic_41/usr/src/cmd/avs/ncall/ncalladm.c (revision fcf3ce441efd61da9bb2884968af01cb7c1452cc)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 #include <sys/types.h>
27 #include <sys/stat.h>
28 #include <strings.h>
29 #include <stdlib.h>
30 #include <unistd.h>
31 #include <errno.h>
32 #include <stdio.h>
33 #include <locale.h>
34 #include <fcntl.h>
35 #include <libgen.h>
36 
37 #include <sys/nsctl/cfg.h>
38 #include <sys/ncall/ncall.h>
39 
40 static CFGFILE *cfg;
41 static int cfg_changed;
42 static char *progname;
43 static ncall_node_t *getnodelist(int, int *, int *);
44 
45 
46 static void
usage(int exitstat)47 usage(int exitstat)
48 {
49 	(void) fprintf(stderr, gettext("usage:\n"));
50 	(void) fprintf(stderr, gettext("       %s -d\n"), progname);
51 	(void) fprintf(stderr, gettext("       %s -e\n"), progname);
52 	(void) fprintf(stderr, gettext("       %s -h\n"), progname);
53 #ifdef DEBUG
54 	(void) fprintf(stderr, gettext("       %s -c [nodeid <nodeid>]\n"),
55 	    progname);
56 	(void) fprintf(stderr, gettext("       %s -i\n"), progname);
57 	(void) fprintf(stderr, gettext("       %s -p <host>\n"), progname);
58 #endif
59 
60 	(void) fprintf(stderr, gettext("where:\n"));
61 	(void) fprintf(stderr, gettext("       -d    disable ncall\n"));
62 	(void) fprintf(stderr, gettext("       -e    enable ncall core\n"));
63 	(void) fprintf(stderr, gettext("       -h    this help message\n"));
64 #ifdef DEBUG
65 	(void) fprintf(stderr,
66 	    gettext("       -c    set or print ncall configuration\n"));
67 	(void) fprintf(stderr, gettext("       -i    ncall information\n"));
68 	(void) fprintf(stderr, gettext("       -p    ncall ping <host>\n"));
69 #endif
70 
71 	exit(exitstat);
72 }
73 
74 
75 static void
ncall_cfg_open(CFGLOCK lk)76 ncall_cfg_open(CFGLOCK lk)
77 {
78 	char hostid[32];
79 
80 	if (cfg != NULL) {
81 		return;
82 	}
83 
84 	if (snprintf(hostid, sizeof (hostid), "%lx", gethostid()) >=
85 	    sizeof (hostid)) {
86 		(void) fprintf(stderr, gettext("%s: hostid %lx too large\n"),
87 		    progname, gethostid());
88 		exit(1);
89 	}
90 
91 	if ((cfg = cfg_open(NULL)) == NULL) {
92 		(void) fprintf(stderr,
93 		    gettext("%s: unable to access the configuration: %s\n"),
94 		    progname, cfg_error(NULL));
95 		exit(1);
96 	}
97 
98 	if (!cfg_lock(cfg, lk)) {
99 		(void) fprintf(stderr,
100 		    gettext("%s: unable to lock the configuration: %s\n"),
101 		    progname, cfg_error(NULL));
102 		exit(1);
103 	}
104 
105 	cfg_resource(cfg, hostid);
106 }
107 
108 
109 static void
ncall_cfg_close(void)110 ncall_cfg_close(void)
111 {
112 	if (cfg_changed && cfg_commit(cfg) < 0) {
113 		(void) fprintf(stderr,
114 		    gettext("%s: unable to update the configuration: %s\n"),
115 		    progname, cfg_error(NULL));
116 		exit(1);
117 	}
118 
119 	cfg_close(cfg);
120 	cfg = NULL;
121 }
122 
123 
124 /*
125  * Get config from dscfg.
126  */
127 static int
get_nodeid_from_cfg(int * nodeid)128 get_nodeid_from_cfg(int *nodeid)
129 {
130 	char buf[CFG_MAX_BUF];
131 	int ret = -1;
132 	int rc;
133 
134 	ncall_cfg_open(CFG_RDLOCK);
135 
136 	if (cfg_get_cstring(cfg, "ncallcore.set1", buf, sizeof (buf)) >= 0) {
137 		rc = sscanf(buf, "%d", nodeid);
138 		if (rc == 1) {
139 			ret = 0;
140 		}
141 	}
142 
143 	ncall_cfg_close();
144 
145 	return (ret);
146 }
147 
148 
149 static void
ncall_print(void)150 ncall_print(void)
151 {
152 	int cfnodeid, clnodeid, rc;
153 
154 	clnodeid = cfg_issuncluster();
155 
156 	rc = get_nodeid_from_cfg(&cfnodeid);
157 
158 	if (rc < 0 && clnodeid > 0) {
159 		(void) printf(gettext("%s: ncall is using the SunCluster "
160 		    "nodeid: %d\n"), progname, clnodeid);
161 	} else if (rc < 0) {
162 		(void) printf(gettext("%s: ncall is using the default "
163 		    "nodeid: %d\n"), progname, 0);
164 	} else {
165 		(void) printf(gettext("%s: current configuration:\n"),
166 		    progname);
167 		/* deliberately not i18n'd - "nodeid" is a keyword */
168 		(void) printf("nodeid %d\n", cfnodeid);
169 	}
170 }
171 
172 
173 static void
ncall_config(const int nodeid)174 ncall_config(const int nodeid)
175 {
176 	char buf[CFG_MAX_BUF];
177 
178 	ncall_cfg_open(CFG_WRLOCK);
179 
180 	if (cfg_get_cstring(cfg, "ncallcore.set1", buf, sizeof (buf)) >= 0) {
181 		/* remove old config */
182 		if (cfg_put_cstring(cfg, "ncallcore.set1", NULL, 0) < 0) {
183 			(void) fprintf(stderr,
184 			    gettext("%s: unable to update the configuration: "
185 			    "%s\n"), cfg_error(NULL));
186 			exit(1);
187 		}
188 	}
189 
190 	if (snprintf(buf, sizeof (buf), "%d", nodeid) >= sizeof (buf)) {
191 		(void) fprintf(stderr,
192 		    gettext("%s: unable to update configuration: "
193 		    "data too long\n"), progname);
194 		exit(1);
195 	}
196 
197 	if (cfg_put_cstring(cfg, "ncallcore", buf, sizeof (buf)) < 0) {
198 		(void) fprintf(stderr,
199 		    gettext("%s: unable to update the configuration: %s\n"),
200 		    cfg_error(NULL));
201 		exit(1);
202 	}
203 
204 	cfg_changed = 1;
205 	ncall_cfg_close();
206 
207 	(void) printf(gettext("%s: configuration set to:\n"), progname);
208 	/* deliberately not i18n'd - "nodeid" is a keyword */
209 	(void) printf("nodeid %d\n", nodeid);
210 }
211 
212 #ifdef lint
213 int
ncalladm_lintmain(int argc,char * argv[])214 ncalladm_lintmain(int argc, char *argv[])
215 #else
216 int
217 main(int argc, char *argv[])
218 #endif
219 {
220 	const char *dev = "/dev/ncall";
221 	extern int optind, opterr;
222 	ncall_node_t nodeinfo, *nodes;
223 	int nsize;
224 	int i;
225 	int cflag, dflag, eflag, iflag, pflag;
226 	int rc, fd, opt;
227 	int clnodeid, cfnodeid;
228 	int up;
229 	char *cp, *ping;
230 	int mnode;	/* mirror nodeid */
231 
232 	(void) setlocale(LC_ALL, "");
233 	(void) textdomain("ncalladm");
234 
235 	opterr = 0;
236 	cflag = dflag = eflag = iflag = pflag = 0;
237 	ping = NULL;
238 
239 	progname = basename(argv[0]);
240 
241 	while ((opt = getopt(argc, argv,
242 #ifdef DEBUG
243 	    "cip:"
244 #endif
245 	    "deh")) != -1) {
246 		switch (opt) {
247 		case 'c':
248 			cflag = 1;
249 			break;
250 
251 		case 'd':
252 			dflag = 1;
253 			break;
254 
255 		case 'e':
256 			eflag = 1;
257 			break;
258 
259 		case 'h':
260 			usage(0);
261 			break;
262 
263 		case 'i':
264 			iflag = 1;
265 			break;
266 
267 		case 'p':
268 			ping = optarg;
269 			pflag = 1;
270 			break;
271 
272 		default:
273 			(void) fprintf(stderr, gettext("%s: unknown option\n"),
274 			    progname);
275 			usage(1);
276 			break;
277 		}
278 	}
279 
280 	if (!(cflag || dflag || eflag || iflag || pflag)) {
281 		usage(1);
282 	}
283 
284 	if (argc != optind) {
285 		if (!cflag ||
286 		    (argc - optind) != 2 ||
287 		    strcmp(argv[optind], "nodeid") != 0) {
288 			usage(1);
289 		}
290 	}
291 
292 	if ((cflag + dflag + eflag + iflag + pflag) > 1) {
293 		(void) fprintf(stderr,
294 		    gettext("%s: multiple options are not supported\n"),
295 		    progname);
296 		usage(1);
297 	}
298 
299 	if (!cflag) {
300 		fd = open(dev, O_RDONLY);
301 		if (fd < 0) {
302 			(void) fprintf(stderr,
303 			    gettext("%s: unable to open %s: %s\n"),
304 			    progname, dev, strerror(errno));
305 			exit(1);
306 		}
307 	}
308 
309 	if (dflag) {
310 		/* ioctl stop into kernel */
311 		if (ioctl(fd, NC_IOC_STOP, 0) < 0) {
312 			(void) fprintf(stderr,
313 			    gettext("%s: unable to disable ncall: %s\n"),
314 			    progname, strerror(errno));
315 			exit(1);
316 		}
317 	} else if (eflag) {
318 		bzero(&nodeinfo, sizeof (nodeinfo));
319 
320 		clnodeid = cfg_issuncluster();
321 		cfnodeid = 0;
322 
323 		/* get node info */
324 		rc = gethostname(nodeinfo.nc_nodename,
325 		    sizeof (nodeinfo.nc_nodename));
326 		if (rc < 0) {
327 			(void) fprintf(stderr,
328 			    gettext("%s: unable to determine hostname: %s\n"),
329 			    progname, strerror(errno));
330 			exit(1);
331 		}
332 
333 		rc = get_nodeid_from_cfg(&cfnodeid);
334 
335 		if (clnodeid > 0 && rc == 0) {
336 			/*
337 			 * check that the nodeids from the cf file and
338 			 * cluster match.
339 			 */
340 			if (clnodeid != cfnodeid) {
341 				(void) fprintf(stderr,
342 				    gettext("%s: nodeid from configuration "
343 				    "(%d) != cluster nodeid (%d)\n"),
344 				    progname, cfnodeid, clnodeid);
345 				exit(1);
346 			}
347 		}
348 
349 		if (rc == 0) {
350 			nodeinfo.nc_nodeid = cfnodeid;
351 		} else if (clnodeid > 0) {
352 			nodeinfo.nc_nodeid = clnodeid;
353 		} else {
354 			nodeinfo.nc_nodeid = 0;
355 		}
356 
357 		/* ioctl node info into kernel and start ncall */
358 		rc = ioctl(fd, NC_IOC_START, &nodeinfo);
359 		if (rc < 0) {
360 			(void) fprintf(stderr,
361 			    gettext("%s: unable to enable ncall: %s\n"),
362 			    progname, strerror(errno));
363 			exit(1);
364 		}
365 	}
366 
367 	if (iflag || pflag) {
368 		nodes = getnodelist(fd, &nsize, &mnode);
369 
370 		if (nodes == NULL) {
371 			(void) fprintf(stderr,
372 			    gettext("%s: unable to get node info\n"),
373 			    progname);
374 			exit(1);
375 		}
376 	}
377 
378 	if (iflag) {
379 		char *mname;
380 		char *pnodestr;
381 
382 		(void) printf(gettext("Self Node Name: %s\n"),
383 		    nodes[0].nc_nodename);
384 		(void) printf(gettext("Self Node ID: %d\n"),
385 		    nodes[0].nc_nodeid);
386 		/*
387 		 * determine which slot is the mirror node.
388 		 */
389 		if (mnode != -1) {
390 			for (i = 1; i < nsize; i++) {
391 				if (nodes[i].nc_nodeid == mnode) {
392 					mname = nodes[i].nc_nodename;
393 					break;
394 				}
395 			}
396 		}
397 		if ((mnode == -1) || (i >= nsize)) {
398 			mname = gettext("unknown");
399 			mnode = -1;
400 		}
401 
402 		(void) printf(gettext("Mirror Node Name: %s\n"), mname);
403 		(void) printf(gettext("Mirror Node ID: %d\n"), mnode);
404 		/*
405 		 * See if we need to translate the node strings.
406 		 */
407 		if (nsize > 1) {
408 			pnodestr = gettext("Node Name: %s\nNode ID: %d\n");
409 			for (i = 1; i < nsize; i++) {
410 				/*
411 				 * Don't print the mirror twice.
412 				 */
413 				if (nodes[i].nc_nodeid != mnode) {
414 					(void) printf(pnodestr,
415 					    nodes[i].nc_nodename,
416 					    nodes[i].nc_nodeid);
417 				}
418 			}
419 		}
420 	}
421 
422 	if (pflag) {
423 		if (strlen(ping) >= sizeof (nodeinfo.nc_nodename)) {
424 			(void) fprintf(stderr,
425 			    gettext("%s: hostname '%s' is too long\n"),
426 			    progname, ping);
427 			exit(1);
428 		}
429 		up = 0;
430 		if (strcmp(nodes[0].nc_nodename, ping) == 0) {
431 			up = 1;		/* self */
432 		} else {
433 			/* not self, so ask kernel */
434 			bzero(&nodeinfo, sizeof (nodeinfo));
435 			/* strlen(ping) checked above */
436 			(void) strcpy(nodeinfo.nc_nodename, ping);
437 			up = ioctl(fd, NC_IOC_PING, nodeinfo);
438 		}
439 
440 		/* model the ping messages on ping(1m) */
441 
442 		if (up < 0) {
443 			(void) fprintf(stderr,
444 			    gettext("%s: unable to ping host '%s': %s\n"),
445 			    progname, ping, strerror(errno));
446 			exit(1);
447 		} else if (up > 0) {
448 			(void) printf(gettext("%s is alive\n"), ping);
449 		} else {
450 			(void) printf(gettext("no answer from %s\n"), ping);
451 			exit(1);
452 		}
453 	}
454 
455 	if (iflag || pflag) {
456 		free(nodes);
457 	}
458 
459 	if (cflag) {
460 		if (argc == optind) {
461 			ncall_print();
462 			return (0);
463 		}
464 
465 		cp = NULL;
466 		cfnodeid = (int)strtol(argv[optind+1], &cp, 0);
467 		if (cp != NULL && *cp != '\0') {
468 			(void) fprintf(stderr,
469 			    gettext("%s: nodeid \"%s\" is not an "
470 			    "integer number\n"), progname, argv[optind+1]);
471 			exit(1);
472 		}
473 
474 		clnodeid = cfg_issuncluster();
475 		if (clnodeid > 0 && cfnodeid != clnodeid) {
476 			(void) fprintf(stderr,
477 			    gettext("%s: nodeid from command line "
478 			    "(%d) != cluster nodeid (%d)\n"),
479 			    progname, cfnodeid, clnodeid);
480 			exit(1);
481 		}
482 
483 		ncall_config(cfnodeid);
484 	}
485 
486 	if (!cflag) {
487 		(void) close(fd);
488 	}
489 
490 	return (0);
491 }
492 
493 
494 /*
495  * return a pointer to a list of currently configured
496  * nodes.
497  * Return the number of nodes via the nodesizep pointer.
498  * Return the mirror nodeid via the mirrorp pointer.
499  * Return NULL on errors.
500  */
501 static ncall_node_t *
getnodelist(int ifd,int * nodesizep,int * mirrorp)502 getnodelist(int ifd, int *nodesizep, int *mirrorp)
503 {
504 	int maxsize;
505 	int cnt;
506 	ncall_node_t *noderet = NULL;
507 	ncall_node_t *nodelist;
508 	ncall_node_t thisnode;
509 	int mirror;
510 	int nonet;
511 
512 	/*
513 	 * Get this host info and mirror nodeid.
514 	 */
515 	mirror = ioctl(ifd, NC_IOC_GETNODE, &thisnode);
516 
517 	if (mirror < 0) {
518 		return (NULL);
519 	}
520 
521 	/*
522 	 * See if we need to allocate the buffer.
523 	 */
524 	nonet = 0;
525 	maxsize = ioctl(ifd, NC_IOC_GETNETNODES, 0);
526 	if (maxsize < 1) {
527 		maxsize = 1;
528 		nonet = 1;
529 	}
530 	nodelist = malloc(sizeof (*nodelist) * maxsize);
531 	if (nodelist) {
532 		if (nonet == 0) {
533 			/*
534 			 * fetch the node data.
535 			 */
536 			cnt = ioctl(ifd, NC_IOC_GETNETNODES, nodelist);
537 			if (cnt > 0) {
538 				*nodesizep = cnt;
539 				noderet = nodelist;
540 				*mirrorp = mirror;
541 			} else {
542 				*nodesizep = 0;
543 				free(nodelist);
544 			}
545 		} else {
546 			(void) memcpy(nodelist, &thisnode, sizeof (*nodelist));
547 			*nodesizep = 1;
548 			noderet = nodelist;
549 			/*
550 			 * Although we know the mirror nodeid, there
551 			 * is no point in returning it as we have
552 			 * no information about any other hosts.
553 			 */
554 			*mirrorp = -1;
555 		}
556 	}
557 	return (noderet);
558 }
559