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, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ 23 /* All Rights Reserved */ 24 /* 25 * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 26 * Use is subject to license terms. 27 */ 28 29 #pragma ident "%Z%%M% %I% %E% SMI" 30 31 32 #include <stdio.h> 33 #include <unistd.h> 34 #include <stdlib.h> 35 #include <fcntl.h> 36 #include <sys/types.h> 37 #include <sys/stropts.h> 38 #include <signal.h> 39 #include <sys/stat.h> 40 #include <poll.h> 41 #include "misc.h" 42 #include "msgs.h" 43 #include "extern.h" 44 #include <sac.h> 45 #include "adm.h" 46 #include "structs.h" 47 48 49 /* 50 * findpm - find a port monitor entry 51 * 52 * args: tag - tag of desired port monitor 53 */ 54 55 56 struct sactab * 57 findpm(tag) 58 register char *tag; 59 { 60 register struct sactab *sp; /* working pointer */ 61 62 for (sp = Sactab; sp; sp = sp->sc_next) { 63 if (!strcmp(tag, sp->sc_tag)) 64 return(sp); 65 } 66 return(NULL); 67 } 68 69 70 /* 71 * sigpoll - handle messages coming in on the command pipe (SIGPOLL signal 72 * handler) 73 */ 74 75 76 void 77 sigpoll() 78 { 79 struct pollfd fds; /* array of fds to poll */ 80 struct admcmd cmd; /* incoming command */ 81 register struct admcmd *ap = &cmd; /* and a pointer to it */ 82 struct admack ack; /* acknowledgment */ 83 register struct admack *ak = &ack; /* and a pointer to it */ 84 register struct sactab *sp; /* working pointer */ 85 struct sacmsg sacmsg; /* message to port monitor */ 86 char **data; /* "dumped" sactab */ 87 char *p; /* scratch pointer */ 88 register int i; /* loop control variable */ 89 int ret; /* return value */ 90 sigset_t cset; /* for signal handling */ 91 sigset_t tset; /* for signal handling */ 92 93 # ifdef DEBUG 94 debug("in sigpoll"); 95 # endif 96 fds.fd = Cfd; 97 fds.events = POLLIN; 98 fds.revents = 0; 99 if (poll(&fds, 1, 0) < 0) 100 error(E_POLL, EXIT); 101 switch (fds.revents) { 102 case POLLIN: 103 if (read(Cfd, ap, sizeof(struct admcmd)) < 0) { 104 error(E_READ, EXIT); 105 } 106 switch (ap->ac_mtype) { 107 108 /* 109 * request to start a port monitor 110 */ 111 112 case AC_START: 113 # ifdef DEBUG 114 (void) sprintf(Scratch, "Got AC_START for <%s>", ap->ac_tag); 115 log(Scratch); 116 # endif 117 if ((sp = findpm(ap->ac_tag)) == NULL) { 118 ak->ak_pid = ap->ac_pid; 119 ak->ak_resp = AK_NOPM; 120 ak->ak_size = 0; 121 sendack(ak); 122 break; 123 } 124 switch (sp->sc_sstate) { 125 case UNKNOWN: 126 ak->ak_pid = ap->ac_pid; 127 ak->ak_resp = AK_RECOVER; 128 ak->ak_size = 0; 129 sendack(ak); 130 break; 131 case FAILED: 132 case NOTRUNNING: 133 sp->sc_rscnt = 0; /* fresh start in life */ 134 if (ret = startpm(sp)) { 135 ak->ak_pid = ap->ac_pid; 136 if (ret == -1) 137 ak->ak_resp = AK_PMLOCK; 138 else 139 ak->ak_resp = AK_REQFAIL; 140 ak->ak_size = 0; 141 sendack(ak); 142 break; 143 } 144 ak->ak_pid = ap->ac_pid; 145 ak->ak_resp = AK_ACK; 146 ak->ak_size = 0; 147 sendack(ak); 148 break; 149 case ENABLED: 150 case DISABLED: 151 case STARTING: 152 case STOPPING: 153 ak->ak_pid = ap->ac_pid; 154 ak->ak_resp = AK_PMRUN; 155 ak->ak_size = 0; 156 sendack(ak); 157 break; 158 } 159 break; 160 161 /* 162 * request to kill a port monitor 163 */ 164 165 case AC_KILL: 166 # ifdef DEBUG 167 (void) sprintf(Scratch, "Got AC_KILL for <%s>", ap->ac_tag); 168 log(Scratch); 169 # endif 170 if ((sp = findpm(ap->ac_tag)) == NULL) { 171 ak->ak_pid = ap->ac_pid; 172 ak->ak_resp = AK_NOPM; 173 ak->ak_size = 0; 174 sendack(ak); 175 break; 176 } 177 switch (sp->sc_sstate) { 178 case UNKNOWN: 179 ak->ak_pid = ap->ac_pid; 180 ak->ak_resp = AK_RECOVER; 181 ak->ak_size = 0; 182 sendack(ak); 183 break; 184 case NOTRUNNING: 185 case FAILED: 186 case STOPPING: 187 ak->ak_pid = ap->ac_pid; 188 ak->ak_resp = AK_PMNOTRUN; 189 ak->ak_size = 0; 190 sendack(ak); 191 break; 192 case STARTING: 193 case ENABLED: 194 case DISABLED: 195 (void) sigprocmask(SIG_SETMASK, NULL, &cset); 196 tset = cset; 197 (void) sigaddset(&tset, SIGALRM); 198 (void) sigaddset(&tset, SIGCLD); 199 (void) sigprocmask(SIG_SETMASK, &tset, NULL); 200 if (sendsig(sp, SIGTERM)) { 201 (void) sprintf(Scratch, "could not send SIGTERM to <%s>", sp->sc_tag); 202 log(Scratch); 203 ak->ak_pid = ap->ac_pid; 204 ak->ak_resp = AK_NOCONTACT; 205 ak->ak_size = 0; 206 sendack(ak); 207 (void) sigprocmask(SIG_SETMASK, &cset, NULL); 208 break; 209 } 210 /* signal sent ok */ 211 sp->sc_lstate = NOTRUNNING; 212 sp->sc_sstate = NOTRUNNING; 213 sp->sc_pstate = STOPPING; 214 ak->ak_pid = ap->ac_pid; 215 ak->ak_resp = AK_ACK; 216 ak->ak_size = 0; 217 sendack(ak); 218 (void) sprintf(Scratch, "terminating <%s>", sp->sc_tag); 219 log(Scratch); 220 (void) sigprocmask(SIG_SETMASK, &cset, NULL); 221 break; 222 } 223 break; 224 225 /* 226 * request to enable a port monitor 227 */ 228 229 case AC_ENABLE: 230 # ifdef DEBUG 231 (void) sprintf(Scratch, "Got AC_ENABLE for <%s>", ap->ac_tag); 232 log(Scratch); 233 # endif 234 if ((sp = findpm(ap->ac_tag)) == NULL) { 235 ak->ak_pid = ap->ac_pid; 236 ak->ak_resp = AK_NOPM; 237 ak->ak_size = 0; 238 sendack(ak); 239 break; 240 } 241 switch (sp->sc_sstate) { 242 case UNKNOWN: 243 ak->ak_pid = ap->ac_pid; 244 ak->ak_resp = AK_RECOVER; 245 ak->ak_size = 0; 246 sendack(ak); 247 break; 248 case NOTRUNNING: 249 case FAILED: 250 case STOPPING: 251 ak->ak_pid = ap->ac_pid; 252 ak->ak_resp = AK_PMNOTRUN; 253 ak->ak_size = 0; 254 sendack(ak); 255 break; 256 case STARTING: 257 case DISABLED: 258 sacmsg.sc_type = SC_ENABLE; 259 sacmsg.sc_size = 0; 260 sp->sc_sstate = ENABLED; 261 sp->sc_lstate = ENABLED; 262 sendpmmsg(sp, &sacmsg); 263 ak->ak_pid = ap->ac_pid; 264 ak->ak_resp = AK_ACK; 265 ak->ak_size = 0; 266 sendack(ak); 267 break; 268 case ENABLED: 269 ak->ak_pid = ap->ac_pid; 270 ak->ak_resp = AK_ACK; 271 ak->ak_size = 0; 272 sendack(ak); 273 break; 274 } 275 break; 276 277 /* 278 * request to disable a port monitor 279 */ 280 281 case AC_DISABLE: 282 # ifdef DEBUG 283 (void) sprintf(Scratch, "Got AC_DISABLE for <%s>", ap->ac_tag); 284 log(Scratch); 285 # endif 286 if ((sp = findpm(ap->ac_tag)) == NULL) { 287 ak->ak_pid = ap->ac_pid; 288 ak->ak_resp = AK_NOPM; 289 ak->ak_size = 0; 290 sendack(ak); 291 break; 292 } 293 switch (sp->sc_sstate) { 294 case UNKNOWN: 295 ak->ak_pid = ap->ac_pid; 296 ak->ak_resp = AK_RECOVER; 297 ak->ak_size = 0; 298 sendack(ak); 299 break; 300 case NOTRUNNING: 301 case FAILED: 302 case STOPPING: 303 ak->ak_pid = ap->ac_pid; 304 ak->ak_resp = AK_PMNOTRUN; 305 ak->ak_size = 0; 306 sendack(ak); 307 break; 308 case STARTING: 309 case ENABLED: 310 sacmsg.sc_type = SC_DISABLE; 311 sacmsg.sc_size = 0; 312 sp->sc_sstate = DISABLED; 313 sp->sc_lstate = DISABLED; 314 sendpmmsg(sp, &sacmsg); 315 ak->ak_pid = ap->ac_pid; 316 ak->ak_resp = AK_ACK; 317 ak->ak_size = 0; 318 sendack(ak); 319 break; 320 case DISABLED: 321 ak->ak_pid = ap->ac_pid; 322 ak->ak_resp = AK_ACK; 323 ak->ak_size = 0; 324 sendack(ak); 325 break; 326 } 327 break; 328 329 /* 330 * request for port monitor status information 331 */ 332 333 case AC_STATUS: 334 # ifdef DEBUG 335 log("Got AC_STATUS"); 336 # endif 337 /* get all the info in one convenient place */ 338 data = dump_table(); 339 if ((data == NULL) && (Nentries > 0)) { 340 /* something bad happened in dump_table */ 341 ak->ak_pid = ap->ac_pid; 342 ak->ak_resp = AK_REQFAIL; 343 ak->ak_size = 0; 344 sendack(ak); 345 break; 346 } 347 /* count how big it is */ 348 ak->ak_size = 0; 349 for (i = 0; i < Nentries; ++i) 350 ak->ak_size += strlen(data[i]); 351 # ifdef DEBUG 352 (void) sprintf(Scratch, "ak_size is %d", ak->ak_size); 353 debug(Scratch); 354 # endif 355 /* get a contiguous chunk */ 356 if ((p = malloc((unsigned) (ak->ak_size + 1))) == NULL) { 357 error(E_MALLOC, CONT); 358 for (i = 0; i < Nentries; ++i) 359 free(data[i]); 360 free((char *) data); 361 ak->ak_pid = ap->ac_pid; 362 ak->ak_resp = AK_REQFAIL; 363 ak->ak_size = 0; 364 sendack(ak); 365 break; 366 } 367 /* condense the data into the contiguous chunk */ 368 *p = '\0'; 369 for (i = 0; i < Nentries; ++i) { 370 (void) strcat(p, data[i]); 371 free(data[i]); 372 } 373 # ifdef DEBUG 374 debug(p); 375 # endif 376 if (data) 377 free((char *) data); 378 /* ak->ak_size was set above */ 379 ak->ak_pid = ap->ac_pid; 380 ak->ak_resp = AK_ACK; 381 sendack(ak); 382 if (ak->ak_size) 383 if (write(Cfd, p, (unsigned) ak->ak_size) != ak->ak_size) 384 log("could not send info"); 385 free(p); 386 break; 387 388 /* 389 * request for sac to read sactab 390 */ 391 392 case AC_SACREAD: 393 # ifdef DEBUG 394 log("Got AC_SACREAD"); 395 # endif 396 ak->ak_pid = ap->ac_pid; 397 ak->ak_resp = AK_ACK; 398 ak->ak_size = 0; 399 read_table(TRUE); 400 sendack(ak); 401 break; 402 403 /* 404 * request for port monitor to read _pmtab 405 */ 406 407 case AC_PMREAD: 408 # ifdef DEBUG 409 (void) sprintf(Scratch, "Got AC_PMREAD for <%s>", ap->ac_tag); 410 log(Scratch); 411 # endif 412 if ((sp = findpm(ap->ac_tag)) == NULL) { 413 ak->ak_pid = ap->ac_pid; 414 ak->ak_resp = AK_NOPM; 415 ak->ak_size = 0; 416 sendack(ak); 417 break; 418 } 419 switch (sp->sc_sstate) { 420 case UNKNOWN: 421 ak->ak_pid = ap->ac_pid; 422 ak->ak_resp = AK_RECOVER; 423 ak->ak_size = 0; 424 sendack(ak); 425 break; 426 case NOTRUNNING: 427 case FAILED: 428 case STOPPING: 429 ak->ak_pid = ap->ac_pid; 430 ak->ak_resp = AK_PMNOTRUN; 431 ak->ak_size = 0; 432 sendack(ak); 433 break; 434 case STARTING: 435 case ENABLED: 436 case DISABLED: 437 sacmsg.sc_type = SC_READDB; 438 sacmsg.sc_size = 0; 439 sendpmmsg(sp, &sacmsg); 440 ak->ak_pid = ap->ac_pid; 441 ak->ak_resp = AK_ACK; 442 ak->ak_size = 0; 443 sendack(ak); 444 break; 445 } 446 break; 447 /* 448 * garbled message 449 */ 450 451 default: 452 (void) sprintf(Scratch, "Got unknown message for <%s>", ap->ac_tag); 453 log(Scratch); 454 ak->ak_pid = ap->ac_pid; 455 ak->ak_resp = AK_UNKNOWN; 456 ak->ak_size = 0; 457 sendack(ak); 458 break; 459 } 460 break; 461 default: 462 error(E_POLL, EXIT); 463 } 464 } 465 466 467 /* 468 * sendack - send a response to the administrative command 469 * 470 * args: ap - pointer to acknowlegment message 471 */ 472 473 void 474 sendack(ap) 475 struct admack *ap; 476 { 477 # ifdef DEBUG 478 debug("in sendack"); 479 # endif 480 if (write(Cfd, ap, sizeof(struct admack)) != sizeof(struct admack)) 481 log("Could not send ack"); 482 } 483 484 485 /* 486 * sendpmmsg - send a message to a PM. Note: sc_size is always 0 in 487 * this version so just send the header. 488 * 489 * args: sp - pointer to sac's port monitor information for 490 * designated port monitor 491 * sm - pointer to message to send 492 */ 493 494 void 495 sendpmmsg(sp, sm) 496 register struct sactab *sp; 497 register struct sacmsg *sm; 498 { 499 char buf[SIZE]; /* scratch buffer */ 500 501 # ifdef DEBUG 502 debug("in sendpmmsg"); 503 # endif 504 if (write(sp->sc_fd, sm, sizeof(struct sacmsg)) != sizeof(struct sacmsg)) { 505 (void) sprintf(buf, "message to <%s> failed", sp->sc_tag); 506 log(buf); 507 } 508 } 509 510 /* 511 * sendsig - send a signal to the port monitor 512 * 513 * args: sp - pointer to sac's port monitor infomation for 514 * designated port monitor 515 * signo - signal number to send 516 */ 517 518 int 519 sendsig(struct sactab *sp, int signo) 520 { 521 pid_t pid; /* pid of designated port monitor */ 522 pid_t checklock(); 523 524 # ifdef DEBUG 525 (void) sprintf(Scratch, "in sendsig - sending signo %d to %s", signo, sp->sc_tag); 526 debug(Scratch); 527 # endif 528 if (pid = checklock(sp)) { 529 if (kill(pid, signo) < 0) { 530 # ifdef DEBUG 531 debug("in sendsig - kill failed"); 532 # endif 533 return(-1); 534 } 535 else 536 return(0); 537 } 538 else { 539 # ifdef DEBUG 540 debug("in sendsig - checklock failed"); 541 # endif 542 return(-1); 543 } 544 } 545 546 547 /* 548 * checklock - check to see if a _pid file is locked 549 * if so, return pid in file, else 0 550 * 551 * args: sp - pointer to sac's port monitor infomation for 552 * designated port monitor 553 */ 554 555 pid_t 556 checklock(sp) 557 register struct sactab *sp; 558 { 559 int fd; /* scratch file descriptor */ 560 char buf[SIZE]; /* scratch buffer */ 561 int ret; /* return value */ 562 563 # ifdef DEBUG 564 debug("in checklock"); 565 # endif 566 (void) sprintf(Scratch, "%s/%s/_pid", HOME, sp->sc_tag); 567 fd = open(Scratch, O_RDONLY); 568 if (fd < 0) { 569 (void) sprintf(Scratch, "can not open _pid file for <%s>", sp->sc_tag); 570 log(Scratch); 571 return((pid_t)0); 572 } 573 if (lockf(fd, F_TEST, 0) < 0) { 574 if ((ret = read(fd, buf, SIZE - 1)) < 0) { 575 (void) close(fd); 576 return((pid_t)0); 577 } 578 (void) close(fd); 579 /* in case pid wasn't null-terminated */ 580 buf[ret] = '\0'; 581 return((pid_t)atol(buf)); 582 } 583 (void) close(fd); 584 return((pid_t)0); 585 } 586