1f6e214c7SGavin Maltby /*
2f6e214c7SGavin Maltby  * CDDL HEADER START
3f6e214c7SGavin Maltby  *
4f6e214c7SGavin Maltby  * The contents of this file are subject to the terms of the
5f6e214c7SGavin Maltby  * Common Development and Distribution License (the "License").
6f6e214c7SGavin Maltby  * You may not use this file except in compliance with the License.
7f6e214c7SGavin Maltby  *
8f6e214c7SGavin Maltby  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9f6e214c7SGavin Maltby  * or http://www.opensolaris.org/os/licensing.
10f6e214c7SGavin Maltby  * See the License for the specific language governing permissions
11f6e214c7SGavin Maltby  * and limitations under the License.
12f6e214c7SGavin Maltby  *
13f6e214c7SGavin Maltby  * When distributing Covered Code, include this CDDL HEADER in each
14f6e214c7SGavin Maltby  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15f6e214c7SGavin Maltby  * If applicable, add the following below this CDDL HEADER, with the
16f6e214c7SGavin Maltby  * fields enclosed by brackets "[]" replaced with your own identifying
17f6e214c7SGavin Maltby  * information: Portions Copyright [yyyy] [name of copyright owner]
18f6e214c7SGavin Maltby  *
19f6e214c7SGavin Maltby  * CDDL HEADER END
20f6e214c7SGavin Maltby  */
21f6e214c7SGavin Maltby 
22f6e214c7SGavin Maltby /*
23f6e214c7SGavin Maltby  * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
24f6e214c7SGavin Maltby  */
25f6e214c7SGavin Maltby 
26f6e214c7SGavin Maltby #include "libscf_impl.h"
27f6e214c7SGavin Maltby 
28f6e214c7SGavin Maltby #include <assert.h>
29f6e214c7SGavin Maltby #include <strings.h>
30f6e214c7SGavin Maltby 
31f6e214c7SGavin Maltby /*
32f6e214c7SGavin Maltby  * Errors returned by smf_notify_{del|get|set}_params()
33f6e214c7SGavin Maltby  */
34f6e214c7SGavin Maltby static const scf_error_t errs_1[] = {
35f6e214c7SGavin Maltby 	SCF_ERROR_BACKEND_ACCESS,
36f6e214c7SGavin Maltby 	SCF_ERROR_BACKEND_READONLY,
37f6e214c7SGavin Maltby 	SCF_ERROR_CONNECTION_BROKEN,
38f6e214c7SGavin Maltby 	SCF_ERROR_DELETED,
39f6e214c7SGavin Maltby 	SCF_ERROR_INTERNAL,
40f6e214c7SGavin Maltby 	SCF_ERROR_INVALID_ARGUMENT,
41f6e214c7SGavin Maltby 	SCF_ERROR_NO_MEMORY,
42f6e214c7SGavin Maltby 	SCF_ERROR_NO_RESOURCES,
43f6e214c7SGavin Maltby 	SCF_ERROR_NOT_FOUND,
44f6e214c7SGavin Maltby 	SCF_ERROR_PERMISSION_DENIED,
45f6e214c7SGavin Maltby 	0
46f6e214c7SGavin Maltby };
47f6e214c7SGavin Maltby 
48f6e214c7SGavin Maltby /*
49f6e214c7SGavin Maltby  * Errors returned by smf_notify_{del|get|set}_params()
50f6e214c7SGavin Maltby  * Except SCF_ERROR_INVALID_ARGUMENT
51f6e214c7SGavin Maltby  */
52f6e214c7SGavin Maltby static const scf_error_t errs_2[] = {
53f6e214c7SGavin Maltby 	SCF_ERROR_BACKEND_ACCESS,
54f6e214c7SGavin Maltby 	SCF_ERROR_BACKEND_READONLY,
55f6e214c7SGavin Maltby 	SCF_ERROR_CONNECTION_BROKEN,
56f6e214c7SGavin Maltby 	SCF_ERROR_DELETED,
57f6e214c7SGavin Maltby 	SCF_ERROR_INTERNAL,
58f6e214c7SGavin Maltby 	SCF_ERROR_NO_MEMORY,
59f6e214c7SGavin Maltby 	SCF_ERROR_NO_RESOURCES,
60f6e214c7SGavin Maltby 	SCF_ERROR_NOT_FOUND,
61f6e214c7SGavin Maltby 	SCF_ERROR_PERMISSION_DENIED,
62f6e214c7SGavin Maltby 	0
63f6e214c7SGavin Maltby };
64f6e214c7SGavin Maltby 
65f6e214c7SGavin Maltby /*
66f6e214c7SGavin Maltby  * Helper function that abort() on unexpected errors.
67f6e214c7SGavin Maltby  * The expected error set is a zero-terminated array of scf_error_t
68f6e214c7SGavin Maltby  */
69f6e214c7SGavin Maltby static int
check_scf_error(scf_error_t e,const scf_error_t * errs)70f6e214c7SGavin Maltby check_scf_error(scf_error_t e, const scf_error_t *errs)
71f6e214c7SGavin Maltby {
72f6e214c7SGavin Maltby 	if (ismember(e, errs))
73f6e214c7SGavin Maltby 		return (1);
74f6e214c7SGavin Maltby 
75f6e214c7SGavin Maltby 	assert(0);
76f6e214c7SGavin Maltby 	abort();
77f6e214c7SGavin Maltby 
78f6e214c7SGavin Maltby 	/*NOTREACHED*/
79f6e214c7SGavin Maltby }
80f6e214c7SGavin Maltby 
81f6e214c7SGavin Maltby /*
82f6e214c7SGavin Maltby  * Mapping of state transition to pgname.
83f6e214c7SGavin Maltby  */
84f6e214c7SGavin Maltby static struct st_pgname {
85f6e214c7SGavin Maltby 	const char	*st_pgname;
86f6e214c7SGavin Maltby 	int32_t		st_state;
87f6e214c7SGavin Maltby } st_pgnames[] = {
88f6e214c7SGavin Maltby 	{ "to-uninitialized", SCF_TRANS(0, SCF_STATE_UNINIT) },
89f6e214c7SGavin Maltby 	{ "from-uninitialized", SCF_TRANS(SCF_STATE_UNINIT, 0) },
90f6e214c7SGavin Maltby 	{ "to-maintenance", SCF_TRANS(0, SCF_STATE_MAINT) },
91f6e214c7SGavin Maltby 	{ "from-maintenance", SCF_TRANS(SCF_STATE_MAINT, 0) },
92f6e214c7SGavin Maltby 	{ "to-offline", SCF_TRANS(0, SCF_STATE_OFFLINE) },
93f6e214c7SGavin Maltby 	{ "from-offline", SCF_TRANS(SCF_STATE_OFFLINE, 0) },
94f6e214c7SGavin Maltby 	{ "to-disabled", SCF_TRANS(0, SCF_STATE_DISABLED) },
95f6e214c7SGavin Maltby 	{ "from-disabled", SCF_TRANS(SCF_STATE_DISABLED, 0) },
96f6e214c7SGavin Maltby 	{ "to-online", SCF_TRANS(0, SCF_STATE_ONLINE) },
97f6e214c7SGavin Maltby 	{ "from-online", SCF_TRANS(SCF_STATE_ONLINE, 0) },
98f6e214c7SGavin Maltby 	{ "to-degraded", SCF_TRANS(0, SCF_STATE_DEGRADED) },
99f6e214c7SGavin Maltby 	{ "from-degraded", SCF_TRANS(SCF_STATE_DEGRADED, 0) },
100f6e214c7SGavin Maltby 	{ NULL, 0 }
101f6e214c7SGavin Maltby };
102f6e214c7SGavin Maltby 
103f6e214c7SGavin Maltby /*
104f6e214c7SGavin Maltby  * Check if class matches or is a subclass of SCF_SVC_TRANSITION_CLASS
105f6e214c7SGavin Maltby  *
106f6e214c7SGavin Maltby  * returns 1, otherwise return 0
107f6e214c7SGavin Maltby  */
108f6e214c7SGavin Maltby static boolean_t
is_svc_stn(const char * class)109f6e214c7SGavin Maltby is_svc_stn(const char *class)
110f6e214c7SGavin Maltby {
111f6e214c7SGavin Maltby 	int n = strlen(SCF_SVC_TRANSITION_CLASS);
112f6e214c7SGavin Maltby 
113f6e214c7SGavin Maltby 	if (class && strncmp(class, SCF_SVC_TRANSITION_CLASS, n) == 0)
114f6e214c7SGavin Maltby 		if (class[n] == '\0' || class[n] == '.')
115f6e214c7SGavin Maltby 			return (1);
116f6e214c7SGavin Maltby 	return (0);
117f6e214c7SGavin Maltby }
118f6e214c7SGavin Maltby 
119f6e214c7SGavin Maltby /*
120f6e214c7SGavin Maltby  * Return the len of the base class. For instance, "class.class1.class2.*"
121f6e214c7SGavin Maltby  * will return the length of "class.class1.class2"
122f6e214c7SGavin Maltby  * This function does not check if the class or base class is valid.
123f6e214c7SGavin Maltby  * A class such as "class.class1....****" is not valid but will return the
124f6e214c7SGavin Maltby  * length of "class.class1....***"
125f6e214c7SGavin Maltby  */
126f6e214c7SGavin Maltby static size_t
base_class_len(const char * c)127f6e214c7SGavin Maltby base_class_len(const char *c)
128f6e214c7SGavin Maltby {
129f6e214c7SGavin Maltby 	const char *p;
130f6e214c7SGavin Maltby 	size_t n;
131f6e214c7SGavin Maltby 
132f6e214c7SGavin Maltby 	if ((n = strlen(c)) == 0)
133f6e214c7SGavin Maltby 		return (0);
134f6e214c7SGavin Maltby 
135f6e214c7SGavin Maltby 	p = c + n;
136f6e214c7SGavin Maltby 
137f6e214c7SGavin Maltby 	/* get rid of any trailing asterisk */
138f6e214c7SGavin Maltby 	if (*--p == '*')
139f6e214c7SGavin Maltby 		n--;
140f6e214c7SGavin Maltby 
141f6e214c7SGavin Maltby 	/* make sure the class doesn't end in '.' */
142f6e214c7SGavin Maltby 	while (p >= c && *--p == '.')
143f6e214c7SGavin Maltby 		n--;
144f6e214c7SGavin Maltby 
145f6e214c7SGavin Maltby 	return (n);
146f6e214c7SGavin Maltby }
147f6e214c7SGavin Maltby 
148f6e214c7SGavin Maltby /*
149f6e214c7SGavin Maltby  * Allocates and builds the pgname for an FMA dotted class.
150f6e214c7SGavin Maltby  * The pgname will be of the form "class.class1.class2,SCF_NOTIFY_PG_POSTFIX"
151f6e214c7SGavin Maltby  *
152f6e214c7SGavin Maltby  * NULL on error
153f6e214c7SGavin Maltby  */
154f6e214c7SGavin Maltby static char *
class_to_pgname(const char * class)155f6e214c7SGavin Maltby class_to_pgname(const char *class)
156f6e214c7SGavin Maltby {
157f6e214c7SGavin Maltby 	size_t n;
158f6e214c7SGavin Maltby 	ssize_t sz = scf_limit(SCF_LIMIT_MAX_NAME_LENGTH) + 1;
159f6e214c7SGavin Maltby 	char *pgname = NULL;
160f6e214c7SGavin Maltby 
161f6e214c7SGavin Maltby 	n = base_class_len(class);
162f6e214c7SGavin Maltby 
163f6e214c7SGavin Maltby 	if (n == 0) {
164f6e214c7SGavin Maltby 		(void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT);
165f6e214c7SGavin Maltby 		return (NULL);
166f6e214c7SGavin Maltby 	}
167f6e214c7SGavin Maltby 
168f6e214c7SGavin Maltby 	if ((pgname = malloc(sz)) == NULL) {
169f6e214c7SGavin Maltby 		(void) scf_set_error(SCF_ERROR_NO_MEMORY);
170f6e214c7SGavin Maltby 		goto error;
171f6e214c7SGavin Maltby 	}
172f6e214c7SGavin Maltby 
173f6e214c7SGavin Maltby 	if (snprintf(pgname, sz, "%.*s,%s", (int)n, class,
174f6e214c7SGavin Maltby 	    SCF_NOTIFY_PG_POSTFIX) >= sz) {
175f6e214c7SGavin Maltby 		(void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT);
176f6e214c7SGavin Maltby 		goto error;
177f6e214c7SGavin Maltby 	}
178f6e214c7SGavin Maltby 	return (pgname);
179f6e214c7SGavin Maltby 
180f6e214c7SGavin Maltby error:
181f6e214c7SGavin Maltby 	free(pgname);
182f6e214c7SGavin Maltby 	pgname = NULL;
183f6e214c7SGavin Maltby 
184f6e214c7SGavin Maltby 	return (pgname);
185f6e214c7SGavin Maltby }
186f6e214c7SGavin Maltby 
187f6e214c7SGavin Maltby /*
188f6e214c7SGavin Maltby  * Get the pg from the running snapshot of the instance (composed or not)
189f6e214c7SGavin Maltby  */
190f6e214c7SGavin Maltby static int
get_pg(scf_service_t * s,scf_instance_t * i,const char * n,scf_propertygroup_t * pg,int composed)191f6e214c7SGavin Maltby get_pg(scf_service_t *s, scf_instance_t *i, const char *n,
192f6e214c7SGavin Maltby     scf_propertygroup_t *pg, int composed)
193f6e214c7SGavin Maltby {
194f6e214c7SGavin Maltby 	scf_handle_t	*h = scf_instance_handle(i);
195f6e214c7SGavin Maltby 	scf_error_t	scf_e = scf_error();
196f6e214c7SGavin Maltby 	scf_snapshot_t	*snap = scf_snapshot_create(h);
197f6e214c7SGavin Maltby 	scf_snaplevel_t	*slvl = scf_snaplevel_create(h);
198f6e214c7SGavin Maltby 	int r = -1;
199f6e214c7SGavin Maltby 
200f6e214c7SGavin Maltby 	if (h == NULL) {
201f6e214c7SGavin Maltby 		/*
202f6e214c7SGavin Maltby 		 * Use the error stored in scf_e
203f6e214c7SGavin Maltby 		 */
204f6e214c7SGavin Maltby 		(void) scf_set_error(scf_e);
205f6e214c7SGavin Maltby 		goto out;
206f6e214c7SGavin Maltby 	}
207f6e214c7SGavin Maltby 	if (s == NULL) {
208f6e214c7SGavin Maltby 		if (snap == NULL || slvl == NULL)
209f6e214c7SGavin Maltby 			goto out;
210f6e214c7SGavin Maltby 		if (scf_instance_get_snapshot(i, "running", snap) != 0)
211f6e214c7SGavin Maltby 			goto out;
212f6e214c7SGavin Maltby 
213f6e214c7SGavin Maltby 		if (composed) {
214f6e214c7SGavin Maltby 			if (scf_instance_get_pg_composed(i, snap, n, pg) != 0)
215