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