changeset 10029:8377504a53e1

6855845 Allow Property Modification in SMF profiles 6855772 svccfg dumps core during installation
author Antonello Cruz <Antonello.Cruz@Sun.COM>
date Thu, 02 Jul 2009 15:41:03 -0700
parents 2de34ea54ad5
children 93a7ff2e6767
files usr/src/cmd/svc/svccfg/svccfg.y usr/src/cmd/svc/svccfg/svccfg_engine.c usr/src/cmd/svc/svccfg/svccfg_libscf.c usr/src/cmd/svc/svccfg/svccfg_xml.c
diffstat 4 files changed, 212 insertions(+), 86 deletions(-) [+]
line wrap: on
line diff
--- a/usr/src/cmd/svc/svccfg/svccfg.y	Thu Jul 02 15:06:50 2009 -0700
+++ b/usr/src/cmd/svc/svccfg/svccfg.y	Thu Jul 02 15:41:03 2009 -0700
@@ -21,7 +21,7 @@
  */
 
 /*
- * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -241,7 +241,23 @@
 	| SCC_RESTORE error terminator	{ synerr(SCC_RESTORE); return(0); }
 
 apply_cmd : SCC_APPLY SCV_WORD terminator
-					{ (void) engine_apply($2); free($2); }
+	{
+		(void) engine_apply($2, 1);
+		free($2);
+	}
+	| SCC_APPLY SCV_WORD SCV_WORD terminator
+	{
+		if (strcmp($2, "-n") == 0) {
+			(void) engine_apply($3, 0);
+			free($2);
+			free($3);
+		} else {
+			synerr(SCC_APPLY);
+			free($2);
+			free($3);
+			return (0);
+		}
+	}
 	| SCC_APPLY error terminator	{ synerr(SCC_APPLY); return(0); }
 
 extract_cmd: SCC_EXTRACT terminator	{ lscf_profile_extract(NULL); }
--- a/usr/src/cmd/svc/svccfg/svccfg_engine.c	Thu Jul 02 15:06:50 2009 -0700
+++ b/usr/src/cmd/svc/svccfg/svccfg_engine.c	Thu Jul 02 15:41:03 2009 -0700
@@ -20,7 +20,7 @@
  */
 
 /*
- * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -637,7 +637,7 @@
 }
 
 int
-engine_apply(const char *file)
+engine_apply(const char *file, int apply_changes)
 {
 	int ret;
 	bundle_t *b;
@@ -657,6 +657,11 @@
 		return (-1);
 	}
 
+	if (!apply_changes) {	/* we don't want to apply, just test */
+		internal_bundle_free(b);
+		return (0);
+	}
+
 	if (lscf_bundle_apply(b, file) != 0) {
 		internal_bundle_free(b);
 		return (-1);
--- a/usr/src/cmd/svc/svccfg/svccfg_libscf.c	Thu Jul 02 15:06:50 2009 -0700
+++ b/usr/src/cmd/svc/svccfg/svccfg_libscf.c	Thu Jul 02 15:41:03 2009 -0700
@@ -2143,6 +2143,7 @@
 		default:
 			bad_error("scf_transaction_commit", scf_error());
 		}
+		break;
 
 	default:
 		bad_error("scf_transaction_commit", r);
@@ -2171,6 +2172,49 @@
  *   EBUSY - new property group changed (error printed)
  */
 static int
+lscf_import_service_pgs(scf_service_t *svc, const char *target_fmri,
+    const entity_t *isvc, int flags)
+{
+	scf_callback_t cbdata;
+
+	cbdata.sc_handle = scf_service_handle(svc);
+	cbdata.sc_parent = svc;
+	cbdata.sc_service = 1;
+	cbdata.sc_general = 0;
+	cbdata.sc_enable = 0;
+	cbdata.sc_flags = flags;
+	cbdata.sc_source_fmri = isvc->sc_fmri;
+	cbdata.sc_target_fmri = target_fmri;
+
+	if (uu_list_walk(isvc->sc_pgroups, entity_pgroup_import, &cbdata,
+	    UU_DEFAULT) != 0) {
+		if (uu_error() != UU_ERROR_CALLBACK_FAILED)
+			bad_error("uu_list_walk", uu_error());
+
+		return (cbdata.sc_err);
+	}
+
+	return (0);
+}
+
+/*
+ * Returns
+ *   0 - success
+ *   ECONNABORTED - repository connection broken
+ *   ENOMEM - out of memory
+ *   ENOSPC - svc.configd is out of resources
+ *   ECANCELED - inst was deleted
+ *   EPERM - could not create property group (permission denied) (error printed)
+ *	   - could not modify property group (permission denied) (error printed)
+ *   EROFS - could not create property group (repository is read-only)
+ *   EACCES - could not create property group (backend access denied)
+ *   EEXIST - could not create property group (already exists)
+ *   EINVAL - invalid property group name (error printed)
+ *	    - invalid property name (error printed)
+ *	    - invalid value (error printed)
+ *   EBUSY - new property group changed (error printed)
+ */
+static int
 lscf_import_instance_pgs(scf_instance_t *inst, const char *target_fmri,
     const entity_t *iinst, int flags)
 {
@@ -7303,6 +7347,69 @@
 	return (result);
 }
 
+/*
+ * _lscf_import_err() summarize the error handling returned by
+ * lscf_import_{instance | service}_pgs
+ * Return values are:
+ * IMPORT_NEXT
+ * IMPORT_OUT
+ * IMPORT_BAD
+ */
+
+#define	IMPORT_BAD	-1
+#define	IMPORT_NEXT	0
+#define	IMPORT_OUT	1
+
+static int
+_lscf_import_err(int err, const char *fmri)
+{
+	switch (err) {
+	case 0:
+		if (g_verbose)
+			warn(gettext("%s updated.\n"), fmri);
+		return (IMPORT_NEXT);
+
+	case ECONNABORTED:
+		warn(gettext("Could not update %s "
+		    "(repository connection broken).\n"), fmri);
+		return (IMPORT_OUT);
+
+	case ENOMEM:
+		warn(gettext("Could not update %s (out of memory).\n"), fmri);
+		return (IMPORT_OUT);
+
+	case ENOSPC:
+		warn(gettext("Could not update %s "
+		    "(repository server out of resources).\n"), fmri);
+		return (IMPORT_OUT);
+
+	case ECANCELED:
+		warn(gettext(
+		    "Could not update %s (deleted).\n"), fmri);
+		return (IMPORT_NEXT);
+
+	case EPERM:
+	case EINVAL:
+	case EBUSY:
+		return (IMPORT_NEXT);
+
+	case EROFS:
+		warn(gettext("Could not update %s (repository read-only).\n"),
+		    fmri);
+		return (IMPORT_OUT);
+
+	case EACCES:
+		warn(gettext("Could not update %s "
+		    "(backend access denied).\n"), fmri);
+		return (IMPORT_NEXT);
+
+	case EEXIST:
+	default:
+		return (IMPORT_BAD);
+	}
+
+	/*NOTREACHED*/
+}
 
 /*
  * Returns
@@ -7316,6 +7423,7 @@
 	scf_scope_t *rscope;
 	scf_service_t *rsvc;
 	scf_instance_t *rinst;
+	scf_iter_t *iter;
 	int annotation_set = 0;
 	int r;
 
@@ -7324,6 +7432,7 @@
 	if ((rscope = scf_scope_create(g_hndl)) == NULL ||
 	    (rsvc = scf_service_create(g_hndl)) == NULL ||
 	    (rinst = scf_instance_create(g_hndl)) == NULL ||
+	    (iter = scf_iter_create(g_hndl)) == NULL ||
 	    (imp_pg = scf_pg_create(g_hndl)) == NULL ||
 	    (imp_tx = scf_transaction_create(g_hndl)) == NULL)
 		scfdie();
@@ -7364,6 +7473,8 @@
 	for (svc = uu_list_first(bndl->sc_bundle_services);
 	    svc != NULL;
 	    svc = uu_list_next(bndl->sc_bundle_services, svc)) {
+		int refresh = 0;
+
 		if (scf_scope_get_service(rscope, svc->sc_name, rsvc) != 0) {
 			switch (scf_error()) {
 			case SCF_ERROR_NOT_FOUND:
@@ -7377,6 +7488,27 @@
 			}
 		}
 
+		/*
+		 * if we have pgs in the profile, we need to refresh ALL
+		 * instances of the service
+		 */
+		if (uu_list_numnodes(svc->sc_pgroups) != 0) {
+			refresh = 1;
+			r = lscf_import_service_pgs(rsvc, svc->sc_fmri, svc,
+			    SCI_FORCE | SCI_KEEP);
+			switch (_lscf_import_err(r, svc->sc_fmri)) {
+			case IMPORT_NEXT:
+				break;
+
+			case IMPORT_OUT:
+				goto out;
+
+			case IMPORT_BAD:
+			default:
+				bad_error("lscf_import_service_pgs", r);
+			}
+		}
+
 		for (inst = uu_list_first(
 		    svc->sc_u.sc_service.sc_service_instances);
 		    inst != NULL;
@@ -7401,57 +7533,30 @@
 
 			r = lscf_import_instance_pgs(rinst, inst->sc_fmri, inst,
 			    SCI_FORCE | SCI_KEEP);
-			switch (r) {
-			case 0:
-				if (g_verbose)
-					warn(gettext("%s updated.\n"),
-					    inst->sc_fmri);
+			switch (_lscf_import_err(r, inst->sc_fmri)) {
+			case IMPORT_NEXT:
 				break;
 
-			case ECONNABORTED:
-				warn(gettext("Could not update %s "
-				    "(repository connection broken).\n"),
-				    inst->sc_fmri);
-				goto out;
-
-			case ENOMEM:
-				warn(gettext("Could not update %s "
-				    "(out of memory).\n"), inst->sc_fmri);
-				goto out;
-
-			case ENOSPC:
-				warn(gettext("Could not update %s "
-				    "(repository server out of resources).\n"),
-				    inst->sc_fmri);
+			case IMPORT_OUT:
 				goto out;
 
-			case ECANCELED:
-				warn(gettext(
-				    "Could not update %s (deleted).\n"),
-				    inst->sc_fmri);
-				break;
-
-			case EPERM:
-			case EINVAL:
-			case EBUSY:
-				break;
-
-			case EROFS:
-				warn(gettext("Could not update %s "
-				    "(repository read-only).\n"),
-				    inst->sc_fmri);
-				goto out;
-
-			case EACCES:
-				warn(gettext("Could not update %s "
-				    "(backend access denied).\n"),
-				    inst->sc_fmri);
-				break;
-
-			case EEXIST:
+			case IMPORT_BAD:
 			default:
 				bad_error("lscf_import_instance_pgs", r);
 			}
+
+			/* refresh only if there is no pgs in the service */
+			if (refresh == 0)
+				(void) refresh_entity(0, rinst, inst->sc_fmri,
+				    NULL, NULL, NULL);
+		}
+
+		if (refresh == 1) {
+			char *name_buf = safe_malloc(max_scf_name_len + 1);
+
+			(void) refresh_entity(1, rsvc, svc->sc_name, rinst,
+			    iter, name_buf);
+			free(name_buf);
 		}
 	}
 
@@ -7466,6 +7571,7 @@
 	scf_pg_destroy(imp_pg);
 	imp_pg = NULL;
 
+	scf_iter_destroy(iter);
 	scf_instance_destroy(rinst);
 	scf_service_destroy(rsvc);
 	scf_scope_destroy(rscope);
--- a/usr/src/cmd/svc/svccfg/svccfg_xml.c	Thu Jul 02 15:06:50 2009 -0700
+++ b/usr/src/cmd/svc/svccfg/svccfg_xml.c	Thu Jul 02 15:41:03 2009 -0700
@@ -2815,18 +2815,19 @@
 
 /*
  * Translate an instance element into an internal property tree, added to
- * service.  If op is SVCCFG_OP_APPLY (i.e., apply a profile), forbid
- * subelements and set the enabled property to override.
+ * service.  If op is SVCCFG_OP_APPLY (i.e., apply a profile), set the
+ * enabled property to override.
  */
 static int
-lxml_get_instance(entity_t *service, xmlNodePtr inst, svccfg_op_t op)
+lxml_get_instance(entity_t *service, xmlNodePtr inst, bundle_type_t bt,
+    svccfg_op_t op)
 {
 	entity_t *i;
 	pgroup_t *pg;
 	property_t *p;
 	xmlNodePtr cursor;
 	xmlChar *enabled;
-	int r;
+	int r, e_val;
 
 	/*
 	 * Fetch its attributes, as appropriate.
@@ -2844,24 +2845,36 @@
 
 	enabled = xmlGetProp(inst, (xmlChar *)enabled_attr);
 
-	/*
-	 * New general property group with enabled boolean property set.
-	 */
-	pg = internal_pgroup_new();
-	(void) internal_attach_pgroup(i, pg);
-
-	pg->sc_pgroup_name = (char *)scf_pg_general;
-	pg->sc_pgroup_type = (char *)scf_group_framework;
-	pg->sc_pgroup_flags = 0;
-
-	p = internal_property_create(SCF_PROPERTY_ENABLED, SCF_TYPE_BOOLEAN, 1,
-	    (uint64_t)(strcmp(true, (const char *)enabled) == 0 ? 1 : 0));
-
-	p->sc_property_override = (op == SVCCFG_OP_APPLY);
-
-	(void) internal_attach_property(pg, p);
-
-	xmlFree(enabled);
+	if (enabled == NULL) {
+		if (bt == SVCCFG_MANIFEST) {
+			semerr(gettext("Instance \"%s\" missing attribute "
+			    "\"%s\".\n"), i->sc_name, enabled_attr);
+			return (-1);
+		}
+	} else {	/* enabled != NULL */
+		if (strcmp(true, (const char *)enabled) != 0 &&
+		    strcmp(false, (const char *)enabled) != 0) {
+			xmlFree(enabled);
+			semerr(gettext("Invalid enabled value\n"));
+			return (-1);
+		}
+		pg = internal_pgroup_new();
+		(void) internal_attach_pgroup(i, pg);
+
+		pg->sc_pgroup_name = (char *)scf_pg_general;
+		pg->sc_pgroup_type = (char *)scf_group_framework;
+		pg->sc_pgroup_flags = 0;
+
+		e_val = (strcmp(true, (const char *)enabled) == 0);
+		p = internal_property_create(SCF_PROPERTY_ENABLED,
+		    SCF_TYPE_BOOLEAN, 1, (uint64_t)e_val);
+
+		p->sc_property_override = (op == SVCCFG_OP_APPLY);
+
+		(void) internal_attach_property(pg, p);
+
+		xmlFree(enabled);
+	}
 
 	/*
 	 * Walk its child elements, as appropriate.
@@ -2871,13 +2884,6 @@
 		if (lxml_ignorable_block(cursor))
 			continue;
 
-		if (op == SVCCFG_OP_APPLY) {
-			semerr(gettext("Instance \"%s\" may not contain "
-			    "elements in profiles.\n"), i->sc_name,
-			    cursor->name);
-			return (-1);
-		}
-
 		switch (lxml_xlate_element(cursor->name)) {
 		case SC_RESTARTER:
 			(void) lxml_get_restarter(i, cursor);
@@ -2972,17 +2978,10 @@
 
 		e = lxml_xlate_element(cursor->name);
 
-		if (op == SVCCFG_OP_APPLY && e != SC_INSTANCE) {
-			semerr(gettext("Service \"%s\" may not contain the "
-			    "non-instance element \"%s\" in a profile.\n"),
-			    s->sc_name, cursor->name);
-
-			return (-1);
-		}
-
 		switch (e) {
 		case SC_INSTANCE:
-			if (lxml_get_instance(s, cursor, op) != 0)
+			if (lxml_get_instance(s, cursor,
+			    bundle->sc_bundle_type, op) != 0)
 				return (-1);
 			break;
 		case SC_TEMPLATE: