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