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