2 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
3 * Use is subject to license terms.
4 * Copyright 2012 Milan Jurik. All rights reserved.
5 * Copyright 2015 Nexenta Systems, Inc. All rights reserved.
11 * Copyright (c) 2007, The Storage Networking Industry Association.
13 * Redistribution and use in source and binary forms, with or without
14 * modification, are permitted provided that the following conditions
16 * - Redistributions of source code must retain the above copyright
17 * notice, this list of conditions and the following disclaimer.
19 * - Redistributions in binary form must reproduce the above copyright
20 * notice, this list of conditions and the following disclaimer in
21 * the documentation and/or other materials provided with the
24 * - Neither the name of The Storage Networking Industry Association (SNIA)
25 * nor the names of its contributors may be used to endorse or promote
26 * products derived from this software without specific prior written
29 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
30 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
31 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
32 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
33 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
34 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
35 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
36 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
37 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
38 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
39 * POSSIBILITY OF SUCH DAMAGE.
43 * NDMP configuration management
52 /* NDMP properties configuration */
53 #define NDMP_GROUP_FMRI_PREFIX "system/ndmpd"
54 #define NDMP_INST "svc:/system/ndmpd:default"
55 #define NDMP_PROP_LEN 600
56 static char *ndmp_pg
[] = {
60 #define NPG (sizeof (ndmp_pg) / sizeof (ndmp_pg[0]))
62 /* Handle Init states */
63 #define NDMP_SCH_STATE_UNINIT 0
64 #define NDMP_SCH_STATE_INITIALIZING 1
65 #define NDMP_SCH_STATE_INIT 2
67 /* NDMP scf handle structure */
68 typedef struct ndmp_scfhandle
{
69 scf_handle_t
*scf_handle
;
71 scf_service_t
*scf_service
;
72 scf_scope_t
*scf_scope
;
73 scf_transaction_t
*scf_trans
;
74 scf_propertygroup_t
*scf_pg
;
77 static int ndmp_config_saveenv(ndmp_scfhandle_t
*, boolean_t
);
78 static ndmp_scfhandle_t
*ndmp_smf_scf_init(const char *);
79 static void ndmp_smf_scf_fini(ndmp_scfhandle_t
*);
80 static int ndmp_smf_start_transaction(ndmp_scfhandle_t
*);
81 static int ndmp_smf_end_transaction(ndmp_scfhandle_t
*, boolean_t
);
82 static int ndmp_smf_set_property(ndmp_scfhandle_t
*, const char *,
84 static int ndmp_smf_get_property(ndmp_scfhandle_t
*, const char *, char *,
86 static int ndmp_smf_create_service_pgroup(ndmp_scfhandle_t
*, const char *);
87 static int ndmp_smf_delete_property(ndmp_scfhandle_t
*, const char *);
88 static int ndmp_smf_get_pg_name(ndmp_scfhandle_t
*, const char *, char **);
91 * This routine send a refresh signal to ndmpd service which cause ndmpd
92 * property table to be refeshed with current ndmpd properties value from SMF.
95 ndmp_service_refresh(void)
97 int rc
= smf_refresh_instance(NDMP_INST
);
100 ndmp_errno
= ENDMP_SMF_INTERNAL
;
105 * Returns value of the specified variable/property. The return value is a
106 * string pointer to the locally allocated memory if the config param is
107 * defined otherwise it would be NULL.
110 ndmp_get_prop(const char *prop
, char **value
)
112 ndmp_scfhandle_t
*handle
;
117 if ((handle
= ndmp_smf_scf_init(NDMP_GROUP_FMRI_PREFIX
)) == NULL
) {
120 if (ndmp_smf_get_pg_name(handle
, prop
, &pgname
)) {
121 ndmp_smf_scf_fini(handle
);
122 ndmp_errno
= ENDMP_SMF_PROP_GRP
;
125 if (ndmp_smf_create_service_pgroup(handle
, pgname
)) {
126 ndmp_smf_scf_fini(handle
);
129 if ((lval
= malloc(NDMP_PROP_LEN
)) == NULL
) {
130 ndmp_smf_scf_fini(handle
);
131 ndmp_errno
= ENDMP_MEM_ALLOC
;
134 if (ndmp_smf_get_property(handle
, prop
, lval
, NDMP_PROP_LEN
) != 0) {
135 ndmp_smf_scf_fini(handle
);
137 ndmp_errno
= ENDMP_SMF_PROP
;
141 ndmp_smf_scf_fini(handle
);
146 ndmp_set_prop(const char *env
, const char *env_val
)
148 ndmp_scfhandle_t
*handle
;
152 if ((handle
= ndmp_smf_scf_init(NDMP_GROUP_FMRI_PREFIX
)) == NULL
)
155 if (ndmp_smf_get_pg_name(handle
, env
, &pgname
)) {
156 ndmp_smf_scf_fini(handle
);
157 ndmp_errno
= ENDMP_SMF_PROP_GRP
;
161 if (ndmp_smf_create_service_pgroup(handle
, pgname
)) {
162 ndmp_smf_scf_fini(handle
);
166 if (ndmp_smf_start_transaction(handle
)) {
167 ndmp_smf_scf_fini(handle
);
172 rc
= ndmp_smf_set_property(handle
, env
, env_val
);
174 rc
= ndmp_smf_delete_property(handle
, env
);
176 if (ndmp_config_saveenv(handle
, (rc
== 0)) == 0)
183 ndmp_smf_get_pg_name(ndmp_scfhandle_t
*h
, const char *pname
, char **pgname
)
186 scf_property_t
*prop
;
189 for (i
= 0; i
< NPG
; i
++) {
190 if (scf_service_get_pg(h
->scf_service
, ndmp_pg
[i
],
194 if ((value
= scf_value_create(h
->scf_handle
)) == NULL
)
197 if ((prop
= scf_property_create(h
->scf_handle
)) == NULL
) {
198 scf_value_destroy(value
);
202 * This will fail if property does not exist in the property
203 * group. Check the next property group in case of failure.
205 if ((scf_pg_get_property(h
->scf_pg
, pname
, prop
)) != 0) {
206 scf_value_destroy(value
);
207 scf_property_destroy(prop
);
211 *pgname
= ndmp_pg
[i
];
212 scf_value_destroy(value
);
213 scf_property_destroy(prop
);
220 * Basically commit the transaction.
223 ndmp_config_saveenv(ndmp_scfhandle_t
*handle
, boolean_t commit
)
227 ret
= ndmp_smf_end_transaction(handle
, commit
);
229 ndmp_smf_scf_fini(handle
);
234 * Must be called when done. Called with the handle allocated in
235 * ndmp_smf_scf_init(), it cleans up the state and frees any SCF resources
239 ndmp_smf_scf_fini(ndmp_scfhandle_t
*handle
)
244 scf_scope_destroy(handle
->scf_scope
);
245 scf_service_destroy(handle
->scf_service
);
246 scf_pg_destroy(handle
->scf_pg
);
247 handle
->scf_state
= NDMP_SCH_STATE_UNINIT
;
248 (void) scf_handle_unbind(handle
->scf_handle
);
249 scf_handle_destroy(handle
->scf_handle
);
254 * Must be called before using any of the SCF functions. Returns
255 * ndmp_scfhandle_t pointer if success.
257 static ndmp_scfhandle_t
*
258 ndmp_smf_scf_init(const char *svc_name
)
260 ndmp_scfhandle_t
*handle
;
262 handle
= (ndmp_scfhandle_t
*)calloc(1, sizeof (ndmp_scfhandle_t
));
263 if (handle
!= NULL
) {
264 handle
->scf_state
= NDMP_SCH_STATE_INITIALIZING
;
265 if (((handle
->scf_handle
=
266 scf_handle_create(SCF_VERSION
)) != NULL
) &&
267 (scf_handle_bind(handle
->scf_handle
) == 0)) {
268 if ((handle
->scf_scope
=
269 scf_scope_create(handle
->scf_handle
)) == NULL
)
272 if (scf_handle_get_local_scope(handle
->scf_handle
,
273 handle
->scf_scope
) != 0)
276 if ((handle
->scf_service
=
277 scf_service_create(handle
->scf_handle
)) == NULL
)
280 if (scf_scope_get_service(handle
->scf_scope
, svc_name
,
281 handle
->scf_service
) != SCF_SUCCESS
)
284 if ((handle
->scf_pg
=
285 scf_pg_create(handle
->scf_handle
)) == NULL
)
288 handle
->scf_state
= NDMP_SCH_STATE_INIT
;
293 ndmp_errno
= ENDMP_MEM_ALLOC
;
298 /* Error handling/unwinding */
300 (void) ndmp_smf_scf_fini(handle
);
301 ndmp_errno
= ENDMP_SMF_INTERNAL
;
306 * Create a new property group at service level.
309 ndmp_smf_create_service_pgroup(ndmp_scfhandle_t
*handle
, const char *pgroup
)
314 * Only create a handle if it doesn't exist. It is ok to exist since
315 * the pg handle will be set as a side effect.
317 if (handle
->scf_pg
== NULL
) {
318 if ((handle
->scf_pg
=
319 scf_pg_create(handle
->scf_handle
)) == NULL
) {
320 ndmp_errno
= ENDMP_SMF_INTERNAL
;
326 * If the pgroup exists, we are done. If it doesn't, then we need to
327 * actually add one to the service instance.
329 if (scf_service_get_pg(handle
->scf_service
,
330 pgroup
, handle
->scf_pg
) != 0) {
331 /* Doesn't exist so create one */
332 if (scf_service_add_pg(handle
->scf_service
, pgroup
,
333 SCF_GROUP_FRAMEWORK
, 0, handle
->scf_pg
) != 0) {
336 case SCF_ERROR_PERMISSION_DENIED
:
337 ndmp_errno
= ENDMP_SMF_PERM
;
340 ndmp_errno
= ENDMP_SMF_INTERNAL
;
349 * Start transaction on current pg in handle. The pg could be service or
350 * instance level. Must be called after pg handle is obtained from create or
354 ndmp_smf_start_transaction(ndmp_scfhandle_t
*handle
)
357 * Lookup the property group and create it if it doesn't already
360 if (handle
->scf_state
== NDMP_SCH_STATE_INIT
) {
361 if ((handle
->scf_trans
=
362 scf_transaction_create(handle
->scf_handle
)) != NULL
) {
363 if (scf_transaction_start(handle
->scf_trans
,
364 handle
->scf_pg
) != 0) {
365 scf_transaction_destroy(handle
->scf_trans
);
366 handle
->scf_trans
= NULL
;
367 ndmp_errno
= ENDMP_SMF_INTERNAL
;
371 ndmp_errno
= ENDMP_SMF_INTERNAL
;
375 if (scf_error() == SCF_ERROR_PERMISSION_DENIED
) {
376 ndmp_errno
= ENDMP_SMF_PERM
;
384 * Commit the changes that were added to the transaction in the handle. Do all
388 ndmp_smf_end_transaction(ndmp_scfhandle_t
*handle
, boolean_t commit
)
393 if (scf_transaction_commit(handle
->scf_trans
) < 0) {
394 ndmp_errno
= ENDMP_SMF_INTERNAL
;
399 scf_transaction_destroy_children(handle
->scf_trans
);
400 scf_transaction_destroy(handle
->scf_trans
);
401 handle
->scf_trans
= NULL
;
407 * Deletes property in current pg
410 ndmp_smf_delete_property(ndmp_scfhandle_t
*handle
, const char *propname
)
412 scf_transaction_entry_t
*entry
= NULL
;
415 * Properties must be set in transactions and don't take effect until
416 * the transaction has been ended/committed.
418 if ((entry
= scf_entry_create(handle
->scf_handle
)) != NULL
) {
419 if (scf_transaction_property_delete(handle
->scf_trans
, entry
,
421 scf_entry_destroy(entry
);
422 ndmp_errno
= ENDMP_SMF_INTERNAL
;
426 ndmp_errno
= ENDMP_SMF_INTERNAL
;
429 if ((scf_error()) == SCF_ERROR_PERMISSION_DENIED
) {
430 ndmp_errno
= ENDMP_SMF_PERM
;
431 scf_entry_destroy(entry
);
439 * Sets property in current pg
442 ndmp_smf_set_property(ndmp_scfhandle_t
*handle
, const char *propname
,
446 scf_value_t
*value
= NULL
;
447 scf_transaction_entry_t
*entry
= NULL
;
448 scf_property_t
*prop
= NULL
;
454 * Properties must be set in transactions and don't take effect until
455 * the transaction has been ended/committed.
457 if (((value
= scf_value_create(handle
->scf_handle
)) == NULL
) ||
458 ((entry
= scf_entry_create(handle
->scf_handle
)) == NULL
) ||
459 ((prop
= scf_property_create(handle
->scf_handle
)) == NULL
) ||
460 (scf_pg_get_property(handle
->scf_pg
, propname
, prop
) != 0) ||
461 (scf_property_get_value(prop
, value
) != 0)) {
466 type
= scf_value_type(value
);
467 if ((scf_transaction_property_change(handle
->scf_trans
, entry
, propname
,
469 (scf_transaction_property_new(handle
->scf_trans
, entry
, propname
,
476 case SCF_TYPE_ASTRING
:
477 if ((scf_value_set_astring(value
, valstr
)) != SCF_SUCCESS
)
480 case SCF_TYPE_INTEGER
:
481 valint
= strtoll(valstr
, 0, 0);
482 scf_value_set_integer(value
, valint
);
484 case SCF_TYPE_BOOLEAN
:
485 if (strncmp(valstr
, "yes", 3))
489 scf_value_set_boolean(value
, valbool
);
494 if (scf_entry_add_value(entry
, value
) == 0) {
495 /* The value is in the transaction */
500 /* The entry is in the transaction */
505 if ((scf_error() == SCF_ERROR_PERMISSION_DENIED
))
506 ndmp_errno
= ENDMP_SMF_PERM
;
508 ndmp_errno
= ENDMP_SMF_INTERNAL
;
510 scf_property_destroy(prop
);
511 scf_value_destroy(value
);
512 scf_entry_destroy(entry
);
517 * Gets a property value.upto sz size. Caller is responsible to have enough
521 ndmp_smf_get_property(ndmp_scfhandle_t
*handle
, const char *propname
,
522 char *valstr
, size_t sz
)
525 scf_value_t
*value
= NULL
;
526 scf_property_t
*prop
= NULL
;
530 char valstrbuf
[NDMP_PROP_LEN
];
532 if (((value
= scf_value_create(handle
->scf_handle
)) != NULL
) &&
533 ((prop
= scf_property_create(handle
->scf_handle
)) != NULL
) &&
534 (scf_pg_get_property(handle
->scf_pg
, propname
, prop
) == 0)) {
535 if (scf_property_get_value(prop
, value
) == 0) {
536 type
= scf_value_type(value
);
538 case SCF_TYPE_ASTRING
:
539 if (scf_value_get_astring(value
, valstr
,
544 case SCF_TYPE_INTEGER
:
545 if (scf_value_get_integer(value
,
550 valstrbuf
[NDMP_PROP_LEN
- 1] = '\0';
551 (void) strncpy(valstr
, lltostr(valint
,
552 &valstrbuf
[NDMP_PROP_LEN
- 1]),
555 case SCF_TYPE_BOOLEAN
:
556 if (scf_value_get_boolean(value
,
562 (void) strncpy(valstr
, "yes", 4);
564 (void) strncpy(valstr
, "no", 3);
575 scf_value_destroy(value
);
576 scf_property_destroy(prop
);