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