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