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 /* 23 * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 /* 30 * RCM module providing support for swap areas 31 * during reconfiguration operations. 32 */ 33 #include <stdlib.h> 34 #include <unistd.h> 35 #include <fcntl.h> 36 #include <thread.h> 37 #include <synch.h> 38 #include <strings.h> 39 #include <assert.h> 40 #include <errno.h> 41 #include <libintl.h> 42 #include <sys/types.h> 43 #include <sys/swap.h> 44 #include <sys/stat.h> 45 #include <sys/param.h> 46 #include <sys/dumpadm.h> 47 #include <sys/wait.h> 48 #include "rcm_module.h" 49 50 /* cache flags */ 51 #define SWAP_CACHE_NEW 0x01 52 #define SWAP_CACHE_STALE 0x02 53 #define SWAP_CACHE_OFFLINED 0x04 54 55 #define SWAP_CMD "/usr/sbin/swap" 56 #define SWAP_DELETE SWAP_CMD" -d %s %ld" 57 #define SWAP_ADD SWAP_CMD" -a %s %ld %ld" 58 59 /* LP64 hard code */ 60 #define MAXOFFSET_STRLEN 20 61 62 typedef struct swap_file { 63 char path[MAXPATHLEN]; 64 int cache_flags; 65 struct swap_area *areas; 66 struct swap_file *next; 67 struct swap_file *prev; 68 } swap_file_t; 69 70 /* swap file may have multiple swap areas */ 71 typedef struct swap_area { 72 off_t start; 73 off_t len; 74 int cache_flags; 75 struct swap_area *next; 76 struct swap_area *prev; 77 } swap_area_t; 78 79 static swap_file_t *cache; 80 static mutex_t cache_lock; 81 82 static int swap_register(rcm_handle_t *); 83 static int swap_unregister(rcm_handle_t *); 84 static int swap_getinfo(rcm_handle_t *, char *, id_t, uint_t, 85 char **, char **, nvlist_t *, rcm_info_t **); 86 static int swap_suspend(rcm_handle_t *, char *, id_t, timespec_t *, 87 uint_t, char **, rcm_info_t **); 88 static int swap_resume(rcm_handle_t *, char *, id_t, uint_t, 89 char **, rcm_info_t **); 90 static int swap_offline(rcm_handle_t *, char *, id_t, uint_t, 91 char **, rcm_info_t **); 92 static int swap_online(rcm_handle_t *, char *, id_t, uint_t, 93 char **, rcm_info_t **); 94 static int swap_remove(rcm_handle_t *, char *, id_t, uint_t, 95 char **, rcm_info_t **); 96 97 static int alloc_usage(char **); 98 static void cache_insert(swap_file_t *); 99 static swap_file_t *cache_lookup(char *); 100 static void cache_remove(swap_file_t *); 101 static void free_cache(void); 102 static int get_dumpdev(char []); 103 static void log_cmd_status(int); 104 static int swap_add(swap_file_t *, char **); 105 static void swap_area_add(swap_file_t *, swap_area_t *); 106 static swap_area_t *swap_area_alloc(swapent_t *); 107 static swap_area_t *swap_area_lookup(swap_file_t *, swapent_t *); 108 static void swap_area_remove(swap_file_t *, swap_area_t *); 109 static int swap_delete(swap_file_t *, char **); 110 static swap_file_t *swap_file_alloc(char *); 111 static void swap_file_free(swap_file_t *); 112 static swaptbl_t *sys_swaptbl(void); 113 static int update_cache(rcm_handle_t *); 114 115 static struct rcm_mod_ops swap_ops = 116 { 117 RCM_MOD_OPS_VERSION, 118 swap_register, 119 swap_unregister, 120 swap_getinfo, 121 swap_suspend, 122 swap_resume, 123 swap_offline, 124 swap_online, 125 swap_remove, 126 NULL, 127 NULL, 128 NULL 129 }; 130 131 struct rcm_mod_ops * 132 rcm_mod_init() 133 { 134 return (&swap_ops); 135 } 136 137 const char * 138 rcm_mod_info() 139 { 140 return ("RCM Swap module %I%"); 141 } 142 143 int 144 rcm_mod_fini() 145 { 146 free_cache(); 147 (void) mutex_destroy(&cache_lock); 148 149 return (RCM_SUCCESS); 150 } 151 152 static int 153 swap_register(rcm_handle_t *hdl) 154 { 155 return (update_cache(hdl)); 156 } 157 158 static int 159 swap_unregister(rcm_handle_t *hdl) 160 { 161 swap_file_t *sf; 162 163 (void) mutex_lock(&cache_lock); 164 while ((sf = cache) != NULL) { 165 cache = cache->next; 166 (void) rcm_unregister_interest(hdl, sf->path, 0); 167 swap_file_free(sf); 168 } 169 (void) mutex_unlock(&cache_lock); 170 171 return (RCM_SUCCESS); 172 } 173 174 /*ARGSUSED*/ 175 static int 176 swap_getinfo(rcm_handle_t *hdl, char *rsrcname, id_t id, uint_t flags, 177 char **infostr, char **errstr, nvlist_t *props, rcm_info_t **dependent) 178 { 179 assert(rsrcname != NULL && infostr != NULL); 180 181 (void) mutex_lock(&cache_lock); 182 if (cache_lookup(rsrcname) == NULL) { 183 rcm_log_message(RCM_ERROR, "unknown resource: %s\n", 184 rsrcname); 185 (void) mutex_unlock(&cache_lock); 186 return (RCM_FAILURE); 187 } 188 (void) mutex_unlock(&cache_lock); 189 (void) alloc_usage(infostr); 190 191 return (RCM_SUCCESS); 192 } 193 194 /* 195 * Remove swap space to maintain availability of anonymous pages 196 * during device suspension. Swap will be reconfigured upon resume. 197 * Fail if operation will unconfigure dump device. 198 */ 199 /*ARGSUSED*/ 200 static int 201 swap_suspend(rcm_handle_t *hdl, char *rsrcname, id_t id, timespec_t *interval, 202 uint_t flags, char **errstr, rcm_info_t **dependent) 203 { 204 swap_file_t *sf; 205 int rv; 206 207 assert(rsrcname != NULL && errstr != NULL); 208 209 if (flags & RCM_QUERY) 210 return (RCM_SUCCESS); 211 212 (void) mutex_lock(&cache_lock); 213 if ((sf = cache_lookup(rsrcname)) == NULL) { 214 (void) mutex_unlock(&cache_lock); 215 return (RCM_SUCCESS); 216 } 217 218 rv = swap_delete(sf, errstr); 219 (void) mutex_unlock(&cache_lock); 220 221 return (rv); 222 } 223 224 /*ARGSUSED*/ 225 static int 226 swap_resume(rcm_handle_t *hdl, char *rsrcname, id_t id, uint_t flags, 227 char **errstr, rcm_info_t **dependent) 228 { 229 swap_file_t *sf; 230 int rv; 231 232 assert(rsrcname != NULL && errstr != NULL); 233 234 (void) mutex_lock(&cache_lock); 235 if ((sf = cache_lookup(rsrcname)) == NULL) { 236 (void) mutex_unlock(&cache_lock); 237 return (RCM_SUCCESS); 238 } 239 240 rv = swap_add(sf, errstr); 241 (void) mutex_unlock(&cache_lock); 242 243 return (rv); 244 } 245 246 /* 247 * By default, reject offline request. If forced, attempt to 248 * delete swap. Fail if operation will unconfigure dump device. 249 */ 250 /*ARGSUSED*/ 251 static int 252 swap_offline(rcm_handle_t *hdl, char *rsrcname, id_t id, uint_t flags, 253 char **errstr, rcm_info_t **dependent) 254 { 255 swap_file_t *sf; 256 int rv; 257 258 assert(rsrcname != NULL && errstr != NULL); 259 260 if ((flags & RCM_FORCE) && (flags & RCM_QUERY)) 261 return (RCM_SUCCESS); 262 263 (void) mutex_lock(&cache_lock); 264 if ((sf = cache_lookup(rsrcname)) == NULL) { 265 (void) mutex_unlock(&cache_lock); 266 return (RCM_SUCCESS); 267 } 268 269 if (flags & RCM_FORCE) { 270 rv = swap_delete(sf, errstr); 271 (void) mutex_unlock(&cache_lock); 272 return (rv); 273 } 274 /* default reject */ 275 (void) mutex_unlock(&cache_lock); 276 (void) alloc_usage(errstr); 277 278 return (RCM_FAILURE); 279 } 280 281 /*ARGSUSED*/ 282 static int 283 swap_online(rcm_handle_t *hdl, char *rsrcname, id_t id, uint_t flags, 284 char **errstr, rcm_info_t **dependent) 285 { 286 swap_file_t *sf; 287 int rv; 288 289 assert(rsrcname != NULL && errstr != NULL); 290 291 (void) mutex_lock(&cache_lock); 292 if ((sf = cache_lookup(rsrcname)) == NULL) { 293 (void) mutex_unlock(&cache_lock); 294 return (RCM_SUCCESS); 295 } 296 297 rv = swap_add(sf, errstr); 298 (void) mutex_unlock(&cache_lock); 299 300 return (rv); 301 } 302 303 /*ARGSUSED*/ 304 static int 305 swap_remove(rcm_handle_t *hdl, char *rsrcname, id_t id, uint_t flags, 306 char **errstr, rcm_info_t **dependent) 307 { 308 swap_file_t *sf; 309 310 assert(rsrcname != NULL); 311 312 (void) mutex_lock(&cache_lock); 313 if ((sf = cache_lookup(rsrcname)) == NULL) { 314 (void) mutex_unlock(&cache_lock); 315 return (RCM_SUCCESS); 316 } 317 /* RCM framework handles unregistration */ 318 cache_remove(sf); 319 swap_file_free(sf); 320 (void) mutex_unlock(&cache_lock); 321 322 return (RCM_SUCCESS); 323 } 324 325 /* 326 * Delete all swap areas for swap file. 327 * Invoke swap(1M) instead of swapctl(2) to 328 * handle relocation of dump device. 329 * If dump device is configured, fail if 330 * unable to relocate dump. 331 * 332 * Call with cache_lock held. 333 */ 334 static int 335 swap_delete(swap_file_t *sf, char **errstr) 336 { 337 swap_area_t *sa; 338 char cmd[sizeof (SWAP_DELETE) + MAXPATHLEN + 339 MAXOFFSET_STRLEN]; 340 char dumpdev[MAXPATHLEN]; 341 int have_dump = 1; 342 int stat; 343 int rv = RCM_SUCCESS; 344 345 if (get_dumpdev(dumpdev) == 0 && dumpdev[0] == '\0') 346 have_dump = 0; 347 348 for (sa = sf->areas; sa != NULL; sa = sa->next) { 349 /* swap(1M) is not idempotent */ 350 if (sa->cache_flags & SWAP_CACHE_OFFLINED) { 351 continue; 352 } 353 354 (void) snprintf(cmd, sizeof (cmd), SWAP_DELETE, sf->path, 355 sa->start); 356 rcm_log_message(RCM_TRACE1, "%s\n", cmd); 357 if ((stat = rcm_exec_cmd(cmd)) != 0) { 358 log_cmd_status(stat); 359 *errstr = strdup(gettext("unable to delete swap")); 360 rv = RCM_FAILURE; 361 goto out; 362 } 363 sa->cache_flags |= SWAP_CACHE_OFFLINED; 364 365 /* 366 * Fail on removal of dump device. 367 */ 368 if (have_dump == 0) 369 continue; 370 371 if (get_dumpdev(dumpdev) != 0) { 372 rcm_log_message(RCM_WARNING, "unable to " 373 "check for removal of dump device\n"); 374 } else if (dumpdev[0] == '\0') { 375 rcm_log_message(RCM_DEBUG, "removed dump: " 376 "attempting recovery\n"); 377 378 /* 379 * Restore dump 380 */ 381 (void) snprintf(cmd, sizeof (cmd), SWAP_ADD, 382 sf->path, sa->start, sa->len); 383 rcm_log_message(RCM_TRACE1, "%s\n", cmd); 384 if ((stat = rcm_exec_cmd(cmd)) != 0) { 385 log_cmd_status(stat); 386 rcm_log_message(RCM_ERROR, 387 "failed to restore dump\n"); 388 } else { 389 sa->cache_flags &= ~SWAP_CACHE_OFFLINED; 390 rcm_log_message(RCM_DEBUG, "dump restored\n"); 391 } 392 *errstr = strdup(gettext("unable to relocate dump")); 393 rv = RCM_FAILURE; 394 goto out; 395 } 396 } 397 sf->cache_flags |= SWAP_CACHE_OFFLINED; 398 out: 399 return (rv); 400 } 401 402 /* 403 * Invoke swap(1M) to add each registered swap area. 404 * 405 * Call with cache_lock held. 406 */ 407 static int 408 swap_add(swap_file_t *sf, char **errstr) 409 { 410 swap_area_t *sa; 411 char cmd[sizeof (SWAP_ADD) + MAXPATHLEN + 412 (2 * MAXOFFSET_STRLEN)]; 413 int stat; 414 int rv = RCM_SUCCESS; 415 416 for (sa = sf->areas; sa != NULL; sa = sa->next) { 417 /* swap(1M) is not idempotent */ 418 if (!(sa->cache_flags & SWAP_CACHE_OFFLINED)) { 419 continue; 420 } 421 422 (void) snprintf(cmd, sizeof (cmd), 423 SWAP_ADD, sf->path, sa->start, sa->len); 424 rcm_log_message(RCM_TRACE1, "%s\n", cmd); 425 if ((stat = rcm_exec_cmd(cmd)) != 0) { 426 log_cmd_status(stat); 427 *errstr = strdup(gettext("unable to add swap")); 428 rv = RCM_FAILURE; 429 break; 430 } else { 431 sa->cache_flags &= ~SWAP_CACHE_OFFLINED; 432 sf->cache_flags &= ~SWAP_CACHE_OFFLINED; 433 } 434 } 435 436 return (rv); 437 } 438 439 static int 440 update_cache(rcm_handle_t *hdl) 441 { 442 swaptbl_t *swt; 443 swap_file_t *sf, *stale_sf; 444 swap_area_t *sa, *stale_sa; 445 int i; 446 int rv = RCM_SUCCESS; 447 448 if ((swt = sys_swaptbl()) == NULL) { 449 rcm_log_message(RCM_ERROR, "failed to read " 450 "current swap configuration\n"); 451 return (RCM_FAILURE); 452 } 453 454 (void) mutex_lock(&cache_lock); 455 456 /* 457 * cache pass 1 - mark everyone stale 458 */ 459 for (sf = cache; sf != NULL; sf = sf->next) { 460 sf->cache_flags |= SWAP_CACHE_STALE; 461 for (sa = sf->areas; sa != NULL; sa = sa->next) { 462 sa->cache_flags |= SWAP_CACHE_STALE; 463 } 464 } 465 466 /* 467 * add new entries 468 */ 469 for (i = 0; i < swt->swt_n; i++) { 470 if (swt->swt_ent[i].ste_flags & (ST_INDEL|ST_DOINGDEL)) { 471 continue; 472 } 473 474 /* 475 * assure swap_file_t 476 */ 477 if ((sf = cache_lookup(swt->swt_ent[i].ste_path)) == NULL) { 478 if ((sf = swap_file_alloc(swt->swt_ent[i].ste_path)) == 479 NULL) { 480 free(swt); 481 return (RCM_FAILURE); 482 } 483 sf->cache_flags |= SWAP_CACHE_NEW; 484 cache_insert(sf); 485 } else { 486 sf->cache_flags &= ~SWAP_CACHE_STALE; 487 } 488 489 /* 490 * assure swap_area_t 491 */ 492 if ((sa = swap_area_lookup(sf, &swt->swt_ent[i])) == NULL) { 493 if ((sa = swap_area_alloc(&swt->swt_ent[i])) == NULL) { 494 free(swt); 495 return (RCM_FAILURE); 496 } 497 swap_area_add(sf, sa); 498 } else { 499 sa->cache_flags &= ~SWAP_CACHE_STALE; 500 } 501 } 502 503 free(swt); 504 505 /* 506 * cache pass 2 507 * 508 * swap_file_t - skip offlined, register new, unregister/remove stale 509 * swap_area_t - skip offlined, remove stale 510 */ 511 sf = cache; 512 while (sf != NULL) { 513 sa = sf->areas; 514 while (sa != NULL) { 515 if (sa->cache_flags & SWAP_CACHE_OFFLINED) { 516 sa->cache_flags &= ~SWAP_CACHE_STALE; 517 sa = sa->next; 518 continue; 519 } 520 if (sa->cache_flags & SWAP_CACHE_STALE) { 521 stale_sa = sa; 522 sa = sa->next; 523 swap_area_remove(sf, stale_sa); 524 free(stale_sa); 525 continue; 526 } 527 sa = sa->next; 528 } 529 530 if (sf->cache_flags & SWAP_CACHE_OFFLINED) { 531 sf->cache_flags &= ~SWAP_CACHE_STALE; 532 sf = sf->next; 533 continue; 534 } 535 536 if (sf->cache_flags & SWAP_CACHE_STALE) { 537 if (rcm_unregister_interest(hdl, sf->path, 0) != 538 RCM_SUCCESS) { 539 rcm_log_message(RCM_ERROR, "failed to register " 540 "%s\n", sf->path); 541 } 542 stale_sf = sf; 543 sf = sf->next; 544 cache_remove(stale_sf); 545 swap_file_free(stale_sf); 546 continue; 547 } 548 549 if (!(sf->cache_flags & SWAP_CACHE_NEW)) { 550 sf = sf->next; 551 continue; 552 } 553 554 if (rcm_register_interest(hdl, sf->path, 0, NULL) != 555 RCM_SUCCESS) { 556 rcm_log_message(RCM_ERROR, "failed to register %s\n", 557 sf->path); 558 rv = RCM_FAILURE; 559 } else { 560 rcm_log_message(RCM_DEBUG, "registered %s\n", 561 sf->path); 562 sf->cache_flags &= ~SWAP_CACHE_NEW; 563 } 564 sf = sf->next; 565 } 566 (void) mutex_unlock(&cache_lock); 567 568 return (rv); 569 } 570 571 /* 572 * Returns system swap table. 573 */ 574 static swaptbl_t * 575 sys_swaptbl() 576 { 577 swaptbl_t *swt; 578 char *cp; 579 int i, n; 580 size_t tbl_size; 581 582 if ((n = swapctl(SC_GETNSWP, NULL)) == -1) 583 return (NULL); 584 585 tbl_size = sizeof (int) + n * sizeof (swapent_t) + n * MAXPATHLEN; 586 if ((swt = (swaptbl_t *)malloc(tbl_size)) == NULL) 587 return (NULL); 588 589 swt->swt_n = n; 590 cp = (char *)swt + (sizeof (int) + n * sizeof (swapent_t)); 591 for (i = 0; i < n; i++) { 592 swt->swt_ent[i].ste_path = cp; 593 cp += MAXPATHLEN; 594 } 595 596 if ((n = swapctl(SC_LIST, swt)) == -1) { 597 free(swt); 598 return (NULL); 599 } 600 601 if (n != swt->swt_n) { 602 /* mismatch, try again */ 603 free(swt); 604 return (sys_swaptbl()); 605 } 606 607 return (swt); 608 } 609 610 static int 611 get_dumpdev(char dumpdev[]) 612 { 613 int fd; 614 int rv = 0; 615 char *err; 616 617 if ((fd = open("/dev/dump", O_RDONLY)) == -1) { 618 rcm_log_message(RCM_ERROR, "failed to open /dev/dump\n"); 619 return (-1); 620 } 621 622 if (ioctl(fd, DIOCGETDEV, dumpdev) == -1) { 623 if (errno == ENODEV) { 624 dumpdev[0] = '\0'; 625 } else { 626 rcm_log_message(RCM_ERROR, "ioctl: %s\n", 627 ((err = strerror(errno)) == NULL) ? "" : err); 628 rv = -1; 629 } 630 } 631 (void) close(fd); 632 633 return (rv); 634 } 635 636 static void 637 free_cache(void) 638 { 639 swap_file_t *sf; 640 641 (void) mutex_lock(&cache_lock); 642 while ((sf = cache) != NULL) { 643 cache = cache->next; 644 swap_file_free(sf); 645 } 646 (void) mutex_unlock(&cache_lock); 647 648 } 649 650 /* 651 * Call with cache_lock held. 652 */ 653 static void 654 swap_file_free(swap_file_t *sf) 655 { 656 swap_area_t *sa; 657 658 assert(sf != NULL); 659 660 while ((sa = sf->areas) != NULL) { 661 sf->areas = sf->areas->next; 662 free(sa); 663 } 664 free(sf); 665 } 666 667 /* 668 * Call with cache_lock held. 669 */ 670 static void 671 cache_insert(swap_file_t *ent) 672 { 673 ent->next = cache; 674 if (ent->next) 675 ent->next->prev = ent; 676 ent->prev = NULL; 677 cache = ent; 678 } 679 680 /* 681 * Call with cache_lock held. 682 */ 683 static swap_file_t * 684 cache_lookup(char *rsrc) 685 { 686 swap_file_t *sf; 687 688 for (sf = cache; sf != NULL; sf = sf->next) { 689 if (strcmp(rsrc, sf->path) == 0) { 690 return (sf); 691 } 692 } 693 return (NULL); 694 } 695 696 /* 697 * Call with cache_lock held. 698 */ 699 static void 700 cache_remove(swap_file_t *ent) 701 { 702 assert(ent != NULL); 703 704 if (ent->next != NULL) { 705 ent->next->prev = ent->prev; 706 } 707 if (ent->prev != NULL) { 708 ent->prev->next = ent->next; 709 } else { 710 cache = ent->next; 711 } 712 ent->next = NULL; 713 ent->prev = NULL; 714 } 715 716 /* 717 * Call with cache_lock held. 718 */ 719 static void 720 swap_area_add(swap_file_t *sf, swap_area_t *sa) 721 { 722 sa->next = sf->areas; 723 if (sa->next) 724 sa->next->prev = sa; 725 sa->prev = NULL; 726 sf->areas = sa; 727 } 728 729 /* 730 * Call with cache_lock held. 731 */ 732 static void 733 swap_area_remove(swap_file_t *sf, swap_area_t *ent) 734 { 735 assert(sf != NULL && ent != NULL); 736 737 if (ent->next != NULL) { 738 ent->next->prev = ent->prev; 739 } 740 if (ent->prev != NULL) { 741 ent->prev->next = ent->next; 742 } else { 743 sf->areas = ent->next; 744 } 745 ent->next = NULL; 746 ent->prev = NULL; 747 } 748 749 static swap_file_t * 750 swap_file_alloc(char *rsrc) 751 { 752 swap_file_t *sf; 753 754 if ((sf = calloc(1, sizeof (*sf))) == NULL) { 755 rcm_log_message(RCM_ERROR, "calloc failure\n"); 756 return (NULL); 757 } 758 (void) strlcpy(sf->path, rsrc, sizeof (sf->path)); 759 760 return (sf); 761 } 762 763 static swap_area_t * 764 swap_area_alloc(swapent_t *swt_ent) 765 { 766 swap_area_t *sa; 767 768 if ((sa = calloc(1, sizeof (*sa))) == NULL) { 769 rcm_log_message(RCM_ERROR, "calloc failure\n"); 770 return (NULL); 771 } 772 sa->start = swt_ent->ste_start; 773 sa->len = swt_ent->ste_length; 774 775 return (sa); 776 } 777 778 /* 779 * Call with cache_lock held. 780 */ 781 static swap_area_t * 782 swap_area_lookup(swap_file_t *sf, swapent_t *swt_ent) 783 { 784 swap_area_t *sa; 785 786 assert(sf != NULL && swt_ent != NULL); 787 assert(strcmp(sf->path, swt_ent->ste_path) == 0); 788 789 for (sa = sf->areas; sa != NULL; sa = sa->next) { 790 if (sa->start == swt_ent->ste_start && 791 sa->len == swt_ent->ste_length) { 792 return (sa); 793 } 794 } 795 return (NULL); 796 } 797 798 /* 799 * All-purpose usage string. 800 */ 801 static int 802 alloc_usage(char **cpp) 803 { 804 if ((*cpp = strdup(gettext("swap area"))) == NULL) { 805 rcm_log_message(RCM_ERROR, "strdup failure\n"); 806 return (-1); 807 } 808 return (0); 809 } 810 811 static void 812 log_cmd_status(int stat) 813 { 814 char *err; 815 816 if (stat == -1) { 817 rcm_log_message(RCM_ERROR, "wait: %s\n", 818 ((err = strerror(errno)) == NULL) ? "" : err); 819 } else if (WIFEXITED(stat)) { 820 rcm_log_message(RCM_ERROR, "exit status: %d\n", 821 WEXITSTATUS(stat)); 822 } else { 823 rcm_log_message(RCM_ERROR, "wait status: %d\n", stat); 824 } 825 } 826