Home | History | Annotate | Download | only in coreadm
      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 }
    688