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 }