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