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 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 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 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 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 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 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 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 * 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