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 * Copyright 2017 RackTop Systems. 26 */ 27 28 #include <stdio.h> 29 #include <fcntl.h> 30 #include <ctype.h> 31 #include <string.h> 32 #include <stdlib.h> 33 #include <unistd.h> 34 #include <errno.h> 35 #include <limits.h> 36 #include <libintl.h> 37 #include <locale.h> 38 #include <sys/stat.h> 39 #include <sys/corectl.h> 40 #include <libproc.h> 41 #include <libscf.h> 42 #include <libscf_priv.h> 43 #include <assert.h> 44 45 #define E_SUCCESS 0 /* Exit status for success */ 46 #define E_ERROR 1 /* Exit status for error */ 47 #define E_USAGE 2 /* Exit status for usage error */ 48 49 static const char PATH_CONFIG[] = "/etc/coreadm.conf"; 50 static const char PATH_CONFIG_OLD[] = "/etc/coreadm.conf.old"; 51 52 #define COREADM_INST_NAME "system/coreadm:default" 53 #define COREADM_INST_FMRI \ 54 SCF_FMRI_SVC_PREFIX SCF_FMRI_SERVICE_PREFIX COREADM_INST_NAME 55 56 #define CONFIG_PARAMS "config_params" 57 #define GLOBAL_ENABLED "global_enabled" 58 #define PROCESS_ENABLED "process_enabled" 59 #define GLOBAL_SETID_ENABLED "global_setid_enabled" 60 #define PROCESS_SETID_ENABLED "process_setid_enabled" 61 #define GLOBAL_LOG_ENABLED "global_log_enabled" 62 #define GLOBAL_PATTERN "global_pattern" 63 #define GLOBAL_CONTENT "global_content" 64 #define INIT_PATTERN "init_pattern" 65 #define INIT_CONTENT "init_content" 66 67 static char *command; 68 static uint64_t options; 69 static int alloptions; 70 static char *glob_pattern; 71 static char gpattern[PATH_MAX]; 72 static core_content_t glob_content = CC_CONTENT_INVALID; 73 static char *init_pattern; 74 static char ipattern[PATH_MAX]; 75 static core_content_t init_content = CC_CONTENT_INVALID; 76 static char *proc_pattern; 77 static size_t proc_size; 78 static core_content_t proc_content = CC_CONTENT_INVALID; 79 80 static int report_settings(void); 81 static int do_processes(int, char **); 82 static int do_modify(void); 83 static int do_update(void); 84 static int do_legacy(void); 85 86 static scf_propvec_t prop_gpattern = { GLOBAL_PATTERN, NULL, SCF_TYPE_ASTRING }; 87 static scf_propvec_t prop_gcontent = { GLOBAL_CONTENT, NULL, SCF_TYPE_ASTRING }; 88 static scf_propvec_t prop_ipattern = { INIT_PATTERN, NULL, SCF_TYPE_ASTRING }; 89 static scf_propvec_t prop_icontent = { INIT_CONTENT, NULL, SCF_TYPE_ASTRING }; 90 static scf_propvec_t prop_option[] = { 91 { GLOBAL_ENABLED, NULL, SCF_TYPE_BOOLEAN, NULL, CC_GLOBAL_PATH }, 92 { PROCESS_ENABLED, NULL, SCF_TYPE_BOOLEAN, NULL, CC_PROCESS_PATH }, 93 { GLOBAL_SETID_ENABLED, NULL, SCF_TYPE_BOOLEAN, NULL, CC_GLOBAL_SETID }, 94 { PROCESS_SETID_ENABLED, NULL, SCF_TYPE_BOOLEAN, NULL, 95 CC_PROCESS_SETID }, 96 { GLOBAL_LOG_ENABLED, NULL, SCF_TYPE_BOOLEAN, NULL, CC_GLOBAL_LOG }, 97 { NULL } 98 }; 99 #define MAX_PROPS (4 + (sizeof (prop_option) / sizeof (scf_propvec_t))) 100 101 static void 102 usage(void) 103 { 104 (void) fprintf(stderr, gettext( 105 "usage:\n")); 106 (void) fprintf(stderr, gettext( 107 " %s [ -g pattern ] [ -i pattern ] [ -G content ] [ -I content ]\n"), 108 command); 109 (void) fprintf(stderr, gettext( 110 " [ -e {global | process | global-setid | proc-setid | log} ]\n")); 111 (void) fprintf(stderr, gettext( 112 " [ -d {global | process | global-setid | proc-setid | log} ]\n")); 113 (void) fprintf(stderr, gettext( 114 " %s [ -p pattern ] [ -P content ] [ pid ... ]\n"), command); 115 exit(E_USAGE); 116 } 117 118 static int 119 perm(void) 120 { 121 (void) fprintf(stderr, gettext("%s: insufficient privileges to " 122 "exercise the -[GIgied] options\n"), command); 123 return (E_USAGE); 124 } 125 126 static int 127 parse_content(char *arg, core_content_t *content) 128 { 129 if (proc_str2content(arg, content) == 0) 130 return (0); 131 (void) fprintf(stderr, gettext("%s: invalid content string '%s'\n"), 132 command, arg); 133 return (1); 134 } 135 136 int 137 main(int argc, char **argv) 138 { 139 int flag; 140 int opt; 141 int modify; 142 int update = 0; 143 int legacy_update = 0; 144 int error = 0; 145 int npids; 146 char **pidlist; 147 148 char curpid[11]; 149 char *curpid_ptr = &curpid[0]; 150 151 (void) setlocale(LC_ALL, ""); 152 (void) textdomain(TEXT_DOMAIN); 153 154 /* command name (e.g., "coreadm") */ 155 if ((command = strrchr(argv[0], '/')) != NULL) 156 command++; 157 else 158 command = argv[0]; 159 160 while ((opt = getopt(argc, argv, "g:G:i:I:p:P:e:d:uU?")) != EOF) { 161 switch (opt) { 162 case 'g': 163 glob_pattern = optarg; 164 break; 165 case 'i': 166 init_pattern = optarg; 167 break; 168 case 'p': 169 proc_pattern = optarg; 170 proc_size = strlen(proc_pattern) + 1; 171 break; 172 case 'G': 173 error |= parse_content(optarg, &glob_content); 174 break; 175 case 'I': 176 error |= parse_content(optarg, &init_content); 177 break; 178 case 'P': 179 error |= parse_content(optarg, &proc_content); 180 break; 181 case 'e': 182 case 'd': 183 if (strcmp(optarg, "global") == 0) 184 flag = CC_GLOBAL_PATH; 185 else if (strcmp(optarg, "process") == 0) 186 flag = CC_PROCESS_PATH; 187 else if (strcmp(optarg, "global-setid") == 0) 188 flag = CC_GLOBAL_SETID; 189 else if (strcmp(optarg, "proc-setid") == 0) 190 flag = CC_PROCESS_SETID; 191 else if (strcmp(optarg, "log") == 0) 192 flag = CC_GLOBAL_LOG; 193 else { 194 flag = 0; 195 error = 1; 196 } 197 if (opt == 'e') 198 options |= flag; 199 else 200 options &= ~flag; 201 alloptions |= flag; 202 break; 203 case 'U': 204 update = 1; 205 break; 206 case 'u': 207 legacy_update = 1; 208 break; 209 case '?': 210 default: 211 error = 1; 212 break; 213 } 214 } 215 216 npids = argc - optind; 217 pidlist = argv + optind; 218 219 if (error) 220 usage(); 221 222 /* 223 * If 'modify' is true, we must modify the system settings 224 * and update the configuration file with the new parameters. 225 */ 226 modify = glob_pattern != NULL || glob_content != CC_CONTENT_INVALID || 227 init_pattern != NULL || init_content != CC_CONTENT_INVALID || 228 alloptions != 0; 229 230 if ((update || legacy_update) && (modify || proc_pattern != NULL || 231 proc_content != CC_CONTENT_INVALID || npids != 0)) { 232 (void) fprintf(stderr, 233 gettext("%s: the -u option must stand alone\n"), command); 234 usage(); 235 } 236 if (modify && 237 (proc_pattern != NULL || proc_content != CC_CONTENT_INVALID)) { 238 (void) fprintf(stderr, gettext( 239 "%s: -[GIgied] and -[Pp] options are mutually exclusive\n"), 240 command); 241 usage(); 242 } 243 if (modify && npids != 0) { 244 (void) fprintf(stderr, gettext( 245 "%s: -[GIgied] options cannot have a process-id list\n"), 246 command); 247 usage(); 248 } 249 if (glob_pattern != NULL && glob_pattern[0] != '/') { 250 (void) fprintf(stderr, gettext( 251 "%s: the -g option must specify an absolute path\n"), 252 command); 253 usage(); 254 } 255 if ((proc_pattern != NULL || proc_content != CC_CONTENT_INVALID) && 256 npids == 0) { 257 (void) sprintf(curpid, "%u", (uint_t)getppid()); 258 npids = 1; 259 pidlist = &curpid_ptr; 260 } 261 262 if (legacy_update) 263 return (do_legacy()); 264 if (update) 265 return (do_update()); 266 if (modify) 267 return (do_modify()); 268 if (npids != 0) 269 return (do_processes(npids, pidlist)); 270 271 return (report_settings()); 272 } 273 274 static int 275 report_settings(void) 276 { 277 char content_str[PRCONTENTBUFSZ]; 278 279 if ((options = core_get_options()) == -1) { 280 perror("core_get_options()"); 281 return (E_ERROR); 282 } 283 if (core_get_global_path(gpattern, sizeof (gpattern)) != 0) { 284 perror("core_get_global_path()"); 285 return (E_ERROR); 286 } 287 if (core_get_default_path(ipattern, sizeof (ipattern)) != 0) { 288 perror("core_get_default_path()"); 289 return (E_ERROR); 290 } 291 if (core_get_global_content(&glob_content) != 0) { 292 perror("core_get_global_content()"); 293 return (E_ERROR); 294 } 295 if (core_get_default_content(&init_content) != 0) { 296 perror("core_get_default_content()"); 297 return (E_ERROR); 298 } 299 300 (void) printf(gettext(" global core file pattern: %s\n"), 301 gpattern); 302 (void) proc_content2str(glob_content, content_str, 303 sizeof (content_str)); 304 (void) printf(gettext(" global core file content: %s\n"), 305 content_str); 306 (void) printf(gettext(" init core file pattern: %s\n"), 307 ipattern); 308 (void) proc_content2str(init_content, content_str, 309 sizeof (content_str)); 310 (void) printf(gettext(" init core file content: %s\n"), 311 content_str); 312 (void) printf(gettext(" global core dumps: %s\n"), 313 (options & CC_GLOBAL_PATH)? "enabled" : "disabled"); 314 (void) printf(gettext(" per-process core dumps: %s\n"), 315 (options & CC_PROCESS_PATH)? "enabled" : "disabled"); 316 (void) printf(gettext(" global setid core dumps: %s\n"), 317 (options & CC_GLOBAL_SETID)? "enabled" : "disabled"); 318 (void) printf(gettext(" per-process setid core dumps: %s\n"), 319 (options & CC_PROCESS_SETID)? "enabled" : "disabled"); 320 (void) printf(gettext(" global core dump logging: %s\n"), 321 (options & CC_GLOBAL_LOG)? "enabled" : "disabled"); 322 return (E_SUCCESS); 323 } 324 325 static int 326 do_processes(int npids, char **pidlist) 327 { 328 char process_path[PATH_MAX]; 329 core_content_t content; 330 pid_t pid; 331 char *next; 332 int rc = E_SUCCESS; 333 char content_str[PRCONTENTBUFSZ]; 334 335 if (proc_pattern == NULL && proc_content == CC_CONTENT_INVALID) { 336 while (npids-- > 0) { 337 pid = strtol(*pidlist, &next, 10); 338 if (*next != '\0' || !isdigit(**pidlist)) { 339 (void) fprintf(stderr, 340 gettext("%s: invalid process-id\n"), 341 *pidlist); 342 rc = E_USAGE; 343 } else if (core_get_process_path(process_path, 344 sizeof (process_path), pid) != 0 || 345 core_get_process_content(&content, pid) != 0) { 346 perror(*pidlist); 347 rc = E_USAGE; 348 } else { 349 (void) proc_content2str(content, content_str, 350 sizeof (content_str)); 351 (void) printf(gettext("%s:\t%s\t%s\n"), 352 *pidlist, process_path, content_str); 353 } 354 pidlist++; 355 } 356 } else { 357 while (npids-- > 0) { 358 pid = strtol(*pidlist, &next, 10); 359 if (*next != '\0') { 360 (void) fprintf(stderr, 361 gettext("%s: invalid process-id\n"), 362 *pidlist); 363 rc = E_USAGE; 364 } else { 365 if (proc_pattern != NULL && 366 core_set_process_path(proc_pattern, 367 proc_size, pid) != 0) { 368 perror(*pidlist); 369 rc = E_USAGE; 370 } 371 372 if (proc_content != CC_CONTENT_INVALID && 373 core_set_process_content( 374 &proc_content, pid) != 0) { 375 perror(*pidlist); 376 rc = E_USAGE; 377 } 378 } 379 pidlist++; 380 } 381 } 382 383 return (rc); 384 } 385 386 static void 387 addprop(scf_propvec_t *props, int size, int count, scf_propvec_t *pv, void *ptr) 388 { 389 assert(count + 1 < size); 390 props[count] = *pv; 391 props[count].pv_ptr = ptr; 392 } 393 394 static int 395 make_active(void) 396 { 397 char *state = smf_get_state(COREADM_INST_FMRI); 398 399 switch (state == NULL ? -1 : smf_state_from_string(state)) { 400 case SCF_STATE_ONLINE: 401 if (smf_refresh_instance_synchronous(COREADM_INST_FMRI) != 0) { 402 (void) fprintf(stderr, 403 gettext("%s: Unable to refresh %s: %s\n"), 404 command, COREADM_INST_FMRI, 405 scf_strerror(scf_error())); 406 return (-1); 407 } 408 break; 409 case SCF_STATE_DEGRADED: 410 case SCF_STATE_MAINT: 411 if (smf_restore_instance_synchronous(COREADM_INST_FMRI) != 0) { 412 (void) fprintf(stderr, 413 gettext("%s: Unable to clear %s: %s\n"), 414 command, COREADM_INST_FMRI, 415 scf_strerror(scf_error())); 416 return (-1); 417 } 418 break; 419 case SCF_STATE_DISABLED: 420 if (smf_enable_instance_synchronous(COREADM_INST_FMRI, 421 0) != 0) { 422 (void) fprintf(stderr, 423 gettext("%s: Unable to enable %s: %s\n"), 424 command, COREADM_INST_FMRI, 425 scf_strerror(scf_error())); 426 return (-1); 427 } 428 break; 429 case SCF_STATE_OFFLINE: 430 default: 431 (void) fprintf(stderr, 432 gettext("%s: coreadm service not online\n"), command); 433 return (-1); 434 } 435 436 return (0); 437 } 438 439 /* 440 * The user has specified the -g, -G, -i, -I, -d, or -e options to 441 * modify the given configuration parameter. Perform the modification 442 * in the smf repository and then perform a smf_refresh_instance which 443 * will cause a coreadm -u to occur which will transfer ALL coreadm 444 * configuration information from the repository to the kernel. 445 */ 446 static int 447 do_modify(void) 448 { 449 char gcontentstr[PRCONTENTBUFSZ]; 450 char icontentstr[PRCONTENTBUFSZ]; 451 scf_propvec_t *prop; 452 scf_propvec_t properties[MAX_PROPS + 1]; 453 int count = 0; 454 455 if (glob_pattern != NULL) 456 addprop(properties, MAX_PROPS, count++, &prop_gpattern, 457 glob_pattern); 458 459 if (glob_content != CC_CONTENT_INVALID) { 460 (void) proc_content2str(glob_content, gcontentstr, 461 sizeof (gcontentstr)); 462 addprop(properties, MAX_PROPS, count++, &prop_gcontent, 463 gcontentstr); 464 } 465 466 if (init_pattern != NULL) 467 addprop(properties, MAX_PROPS, count++, &prop_ipattern, 468 init_pattern); 469 470 if (init_content != CC_CONTENT_INVALID) { 471 (void) proc_content2str(init_content, icontentstr, 472 sizeof (icontentstr)); 473 addprop(properties, MAX_PROPS, count++, &prop_icontent, 474 icontentstr); 475 } 476 477 for (prop = prop_option; prop->pv_prop != NULL; prop++) 478 if ((alloptions & prop->pv_aux) != 0) 479 addprop(properties, MAX_PROPS, count++, prop, &options); 480 481 properties[count].pv_prop = NULL; 482 483 prop = NULL; 484 if (scf_write_propvec(COREADM_INST_FMRI, CONFIG_PARAMS, properties, 485 &prop) == SCF_FAILED) { 486 if (prop != NULL) { 487 (void) fprintf(stderr, gettext( 488 "%s: Unable to write property '%s': %s"), command, 489 prop->pv_prop, scf_strerror(scf_error())); 490 } else { 491 (void) fprintf(stderr, gettext( 492 "%s: Unable to write configuration: %s\n"), 493 command, scf_strerror(scf_error())); 494 } 495 return (E_ERROR); 496 } 497 498 if (make_active() != 0) { 499 (void) fprintf(stderr, gettext( 500 "Configuration stored but not made active.\n")); 501 return (E_ERROR); 502 } 503 504 return (E_SUCCESS); 505 } 506 507 static const char * 508 write_kernel(void) 509 { 510 if (core_set_global_path(glob_pattern, strlen(glob_pattern) + 1) != 0) 511 return ("core_set_global_path()"); 512 513 if (core_set_global_content(&glob_content) != 0) 514 return ("core_set_global_content()"); 515 516 if (core_set_default_path(init_pattern, strlen(init_pattern) + 1) != 0) 517 return ("core_set_default_path()"); 518 519 if (core_set_default_content(&init_content) != 0) 520 return ("core_set_init_content()"); 521 522 if (core_set_options((int)options) != 0) 523 return ("core_set_options()"); 524 525 return (NULL); 526 } 527 528 /* 529 * BUFSIZE must be large enough to contain the longest path plus some more. 530 */ 531 #define BUFSIZE (PATH_MAX + 80) 532 533 static int 534 yes(char *name, char *value, int line) 535 { 536 if (strcmp(value, "yes") == 0) 537 return (1); 538 if (strcmp(value, "no") == 0) 539 return (0); 540 (void) fprintf(stderr, gettext( 541 "\"%s\", line %d: warning: value must be yes or no: %s=%s\n"), 542 PATH_CONFIG, line, name, value); 543 return (0); 544 } 545 546 static int 547 read_legacy(void) 548 { 549 FILE *fp; 550 int line; 551 char buf[BUFSIZE]; 552 char name[BUFSIZE], value[BUFSIZE]; 553 int n, len; 554 555 /* defaults */ 556 alloptions = CC_OPTIONS; 557 options = CC_PROCESS_PATH; 558 gpattern[0] = '\0'; 559 (void) strcpy(ipattern, "core"); 560 glob_content = init_content = CC_CONTENT_DEFAULT; 561 562 glob_pattern = gpattern; 563 init_pattern = ipattern; 564 565 if ((fp = fopen(PATH_CONFIG, "r")) == NULL) 566 return (0); 567 568 for (line = 1; fgets(buf, sizeof (buf), fp) != NULL; line++) { 569 /* 570 * Skip comment lines and empty lines. 571 */ 572 if (buf[0] == '#' || buf[0] == '\n') 573 continue; 574 /* 575 * Look for "name=value", with optional whitespace on either 576 * side, terminated by a newline, and consuming the whole line. 577 */ 578 /* LINTED - unbounded string specifier */ 579 n = sscanf(buf, " %[^=]=%s \n%n", name, value, &len); 580 if (n >= 1 && name[0] != '\0' && 581 (n == 1 || len == strlen(buf))) { 582 if (n == 1) 583 value[0] = '\0'; 584 if (strcmp(name, "COREADM_GLOB_PATTERN") == 0) { 585 (void) strcpy(gpattern, value); 586 continue; 587 } 588 if (strcmp(name, "COREADM_GLOB_CONTENT") == 0) { 589 (void) proc_str2content(value, &glob_content); 590 continue; 591 } 592 if (strcmp(name, "COREADM_INIT_PATTERN") == 0) { 593 (void) strcpy(ipattern, value); 594 continue; 595 } 596 if (strcmp(name, "COREADM_INIT_CONTENT") == 0) { 597 (void) proc_str2content(value, &init_content); 598 continue; 599 } 600 if (strcmp(name, "COREADM_GLOB_ENABLED") == 0) { 601 if (yes(name, value, line)) 602 options |= CC_GLOBAL_PATH; 603 continue; 604 } 605 if (strcmp(name, "COREADM_PROC_ENABLED") == 0) { 606 if (yes(name, value, line)) 607 options |= CC_PROCESS_PATH; 608 else 609 options &= ~CC_PROCESS_PATH; 610 continue; 611 } 612 if (strcmp(name, "COREADM_GLOB_SETID_ENABLED") == 0) { 613 if (yes(name, value, line)) 614 options |= CC_GLOBAL_SETID; 615 continue; 616 } 617 if (strcmp(name, "COREADM_PROC_SETID_ENABLED") == 0) { 618 if (yes(name, value, line)) 619 options |= CC_PROCESS_SETID; 620 continue; 621 } 622 if (strcmp(name, "COREADM_GLOB_LOG_ENABLED") == 0) { 623 if (yes(name, value, line)) 624 options |= CC_GLOBAL_LOG; 625 continue; 626 } 627 (void) fprintf(stderr, gettext( 628 "\"%s\", line %d: warning: invalid token: %s\n"), 629 PATH_CONFIG, line, name); 630 } else { 631 (void) fprintf(stderr, 632 gettext("\"%s\", line %d: syntax error\n"), 633 PATH_CONFIG, line); 634 } 635 } 636 (void) fclose(fp); 637 638 return (1); 639 } 640 641 /* 642 * Loads and applies the coreadm configuration stored in the default 643 * coreadm instance. As this option is (only) used from within an SMF 644 * service method, this function must return an SMF_EXIT_* exit status 645 * to its caller. 646 */ 647 static int 648 do_update(void) 649 { 650 char *gcstr, *icstr; 651 scf_propvec_t properties[MAX_PROPS + 1]; 652 scf_propvec_t *prop; 653 int count = 0; 654 const char *errstr; 655 656 if (read_legacy()) { 657 if ((errstr = write_kernel()) != NULL) 658 goto error; 659 660 if (do_modify() != 0 || 661 rename(PATH_CONFIG, PATH_CONFIG_OLD) != 0) { 662 (void) fprintf(stderr, gettext( 663 "%s: failed to import legacy configuration.\n"), 664 command); 665 return (SMF_EXIT_ERR_FATAL); 666 } 667 return (SMF_EXIT_OK); 668 } 669 670 addprop(properties, MAX_PROPS, count++, &prop_gpattern, &glob_pattern); 671 addprop(properties, MAX_PROPS, count++, &prop_gcontent, &gcstr); 672 addprop(properties, MAX_PROPS, count++, &prop_ipattern, &init_pattern); 673 addprop(properties, MAX_PROPS, count++, &prop_icontent, &icstr); 674 for (prop = prop_option; prop->pv_prop != NULL; prop++) 675 addprop(properties, MAX_PROPS, count++, prop, &options); 676 properties[count].pv_prop = NULL; 677 678 alloptions = CC_OPTIONS; 679 if (scf_read_propvec(COREADM_INST_FMRI, CONFIG_PARAMS, B_FALSE, 680 properties, &prop) == SCF_FAILED) { 681 if (prop != NULL) { 682 (void) fprintf(stderr, gettext( 683 "%s: configuration property '%s' not found.\n"), 684 command, prop->pv_prop); 685 } else { 686 (void) fprintf(stderr, gettext( 687 "%s: unable to read configuration: %s\n"), 688 command, scf_strerror(scf_error())); 689 } 690 return (SMF_EXIT_ERR_FATAL); 691 } 692 693 (void) proc_str2content(gcstr, &glob_content); 694 (void) proc_str2content(icstr, &init_content); 695 696 errstr = write_kernel(); 697 scf_clean_propvec(properties); 698 if (errstr == NULL) 699 return (SMF_EXIT_OK); 700 701 error: 702 if (errno == EPERM) { 703 (void) perm(); 704 return (SMF_EXIT_ERR_PERM); 705 } 706 perror(errstr); 707 return (errno == EINVAL ? SMF_EXIT_ERR_CONFIG : SMF_EXIT_ERR_FATAL); 708 } 709 710 static int do_legacy() 711 { 712 const char *errstr; 713 714 if (read_legacy() && (errstr = write_kernel()) != NULL) { 715 if (errno == EPERM) 716 return (perm()); 717 perror(errstr); 718 return (E_ERROR); 719 } 720 721 return (E_SUCCESS); 722 }