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 (c) 2010, Oracle and/or its affiliates. All rights reserved.
23 */
24#include <stdio.h>
25#include <stdlib.h>
26#include <syslog.h>
27#include <stdarg.h>
28#include "smfcfg.h"
29
30fs_smfhandle_t *
31fs_smf_init(char *fmri, char *instance)
32{
33	fs_smfhandle_t *handle = NULL;
34	char *svcname, srv[MAXPATHLEN];
35
36	/*
37	 * svc name is of the form svc://network/fs/server:instance1
38	 * FMRI portion is /network/fs/server
39	 */
40	snprintf(srv, MAXPATHLEN, "%s", fmri + strlen("svc:/"));
41	svcname = strrchr(srv, ':');
42	if (svcname != NULL)
43		*svcname = '\0';
44	svcname = srv;
45
46	handle = calloc(1, sizeof (fs_smfhandle_t));
47	if (handle != NULL) {
48		handle->fs_handle = scf_handle_create(SCF_VERSION);
49		if (handle->fs_handle == NULL)
50			goto out;
51		if (scf_handle_bind(handle->fs_handle) != 0)
52			goto out;
53		handle->fs_service =
54		    scf_service_create(handle->fs_handle);
55		handle->fs_scope =
56		    scf_scope_create(handle->fs_handle);
57		if (scf_handle_get_local_scope(handle->fs_handle,
58		    handle->fs_scope) != 0)
59			goto out;
60		if (scf_scope_get_service(handle->fs_scope,
61		    svcname, handle->fs_service)  != SCF_SUCCESS) {
62			goto out;
63		}
64		handle->fs_pg =
65		    scf_pg_create(handle->fs_handle);
66		handle->fs_instance =
67		    scf_instance_create(handle->fs_handle);
68		handle->fs_property =
69		    scf_property_create(handle->fs_handle);
70		handle->fs_value =
71		    scf_value_create(handle->fs_handle);
72	} else {
73		fprintf(stderr,
74		    gettext("Cannot access SMF repository: %s\n"), fmri);
75	}
76	return (handle);
77
78out:
79	fs_smf_fini(handle);
80	fprintf(stderr, gettext("SMF Initialization problems..%s\n"), fmri);
81	return (NULL);
82}
83
84
85void
86fs_smf_fini(fs_smfhandle_t *handle)
87{
88	if (handle != NULL) {
89		scf_scope_destroy(handle->fs_scope);
90		scf_instance_destroy(handle->fs_instance);
91		scf_service_destroy(handle->fs_service);
92		scf_pg_destroy(handle->fs_pg);
93		scf_property_destroy(handle->fs_property);
94		scf_value_destroy(handle->fs_value);
95		if (handle->fs_handle != NULL) {
96			scf_handle_unbind(handle->fs_handle);
97			scf_handle_destroy(handle->fs_handle);
98		}
99		free(handle);
100	}
101}
102
103int
104fs_smf_set_prop(smf_fstype_t fstype, char *prop_name, char *valbuf,
105    char *instance, scf_type_t sctype, char *fmri)
106{
107	fs_smfhandle_t *phandle;
108	scf_handle_t *handle;
109	scf_propertygroup_t *pg;
110	scf_property_t *prop;
111	scf_transaction_t *tran;
112	scf_transaction_entry_t *entry;
113	scf_instance_t *inst;
114	scf_value_t *val;
115	int valint;
116	int index = 0;
117	int ret = 0;
118	char *p = NULL;
119	char *svcname, srv[MAXPATHLEN];
120	const char *pgname;
121
122	/*
123	 * The SVC names we are using currently are already
124	 * appended by default. Fix this for instances project.
125	 */
126	snprintf(srv, MAXPATHLEN, "%s", fmri);
127	p = strstr(fmri, ":default");
128	if (p == NULL) {
129		strcat(srv, ":");
130		if (instance == NULL)
131			instance = "default";
132		if (strlen(srv) + strlen(instance) > MAXPATHLEN)
133			goto out;
134		strncat(srv, instance, strlen(instance));
135	}
136	svcname = srv;
137	phandle = fs_smf_init(fmri, instance);
138	if (phandle == NULL) {
139		return (SMF_SYSTEM_ERR);
140	}
141	handle = phandle->fs_handle;
142	pg = phandle->fs_pg;
143	prop = phandle->fs_property;
144	inst = phandle->fs_instance;
145	val = phandle->fs_value;
146	tran = scf_transaction_create(handle);
147	entry = scf_entry_create(handle);
148
149	if (handle == NULL || pg == NULL || prop == NULL ||
150	    val == NULL|| tran == NULL || entry == NULL || inst == NULL) {
151		ret = SMF_SYSTEM_ERR;
152		goto out;
153	}
154
155	if (scf_handle_decode_fmri(handle, svcname, phandle->fs_scope,
156	    phandle->fs_service, inst, NULL, NULL, 0) != 0) {
157		ret = scf_error();
158		goto out;
159	}
160	if (fstype == AUTOFS_SMF)
161		pgname = AUTOFS_PROPS_PGNAME;
162	else
163		pgname = NFS_PROPS_PGNAME;
164
165	if (scf_instance_get_pg(inst, pgname,
166	    pg) != -1) {
167		uint8_t	vint;
168		if (scf_transaction_start(tran, pg) == -1) {
169			ret = scf_error();
170			goto out;
171		}
172		switch (sctype) {
173		case SCF_TYPE_INTEGER:
174			errno = 0;
175			valint = strtoul(valbuf, NULL, 0);
176			if (errno != 0) {
177				ret = SMF_SYSTEM_ERR;
178				goto out;
179			}
180			if (scf_transaction_property_change(tran,
181			    entry, prop_name, SCF_TYPE_INTEGER) == 0) {
182				scf_value_set_integer(val, valint);
183				if (scf_entry_add_value(entry, val) < 0) {
184					ret = scf_error();
185					goto out;
186				}
187			}
188			break;
189		case SCF_TYPE_ASTRING:
190			if (scf_transaction_property_change(tran, entry,
191			    prop_name, SCF_TYPE_ASTRING) == 0) {
192				if (scf_value_set_astring(val,
193				    valbuf) == 0) {
194					if (scf_entry_add_value(entry,
195					    val) != 0) {
196						ret = scf_error();
197						goto out;
198					}
199				} else
200					ret = SMF_SYSTEM_ERR;
201			} else
202				ret = SMF_SYSTEM_ERR;
203			break;
204		case SCF_TYPE_BOOLEAN:
205			if (strcmp(valbuf, "1") == 0) {
206				vint = 1;
207			} else if (strcmp(valbuf, "0") == 0) {
208				vint = 0;
209			} else  {
210				ret = SMF_SYSTEM_ERR;
211				break;
212			}
213			if (scf_transaction_property_change(tran, entry,
214			    prop_name, SCF_TYPE_BOOLEAN) == 0) {
215				scf_value_set_boolean(val, (uint8_t)vint);
216				if (scf_entry_add_value(entry, val) != 0) {
217					ret = scf_error();
218					goto out;
219				}
220			} else {
221				ret = SMF_SYSTEM_ERR;
222			}
223			break;
224		}
225		if (ret != SMF_SYSTEM_ERR)
226			scf_transaction_commit(tran);
227	}
228out:
229	if (tran != NULL)
230		scf_transaction_destroy(tran);
231	if (entry != NULL)
232		scf_entry_destroy(entry);
233	fs_smf_fini(phandle);
234	return (ret);
235}
236
237int
238fs_smf_get_prop(smf_fstype_t fstype, char *prop_name, char *cbuf,
239    char *instance, scf_type_t sctype, char *fmri, int *bufsz)
240{
241	fs_smfhandle_t *phandle;
242	scf_handle_t *handle;
243	scf_propertygroup_t *pg;
244	scf_property_t *prop;
245	scf_value_t *val;
246	scf_instance_t *inst;
247	int ret = 0, len = 0, length;
248	int64_t valint = 0;
249	char srv[MAXPATHLEN], *p, *svcname;
250	const char *pgname;
251	uint8_t bval;
252
253	/*
254	 * The SVC names we are using currently are already
255	 * appended by default. Fix this for instances project.
256	 */
257	snprintf(srv, MAXPATHLEN, "%s", fmri);
258	p = strstr(fmri, ":default");
259	if (p == NULL) {
260		strcat(srv, ":");
261		if (instance == NULL)
262			instance = "default";
263		if (strlen(srv) + strlen(instance) > MAXPATHLEN)
264			goto out;
265		strncat(srv, instance, strlen(instance));
266	}
267	svcname = srv;
268	phandle = fs_smf_init(fmri, instance);
269	if (phandle == NULL)
270		return (SMF_SYSTEM_ERR);
271	handle = phandle->fs_handle;
272	pg = phandle->fs_pg;
273	inst = phandle->fs_instance;
274	prop = phandle->fs_property;
275	val = phandle->fs_value;
276
277	if (handle == NULL || pg == NULL || prop == NULL || val == NULL ||
278	    inst == NULL)  {
279		return (SMF_SYSTEM_ERR);
280	}
281
282
283	if (scf_handle_decode_fmri(handle, svcname, phandle->fs_scope,
284	    phandle->fs_service, inst, NULL, NULL, 0) != 0) {
285		ret = scf_error();
286		goto out;
287	}
288
289	if (fstype == AUTOFS_SMF)
290		pgname = AUTOFS_PROPS_PGNAME;
291	else
292		pgname = NFS_PROPS_PGNAME;
293
294	if (scf_instance_get_pg(inst, pgname, pg) != -1) {
295		if (scf_pg_get_property(pg, prop_name,
296		    prop) != SCF_SUCCESS) {
297			ret = scf_error();
298			goto out;
299		}
300		if (scf_property_get_value(prop, val) != SCF_SUCCESS) {
301			ret = scf_error();
302			goto out;
303		}
304		switch (sctype) {
305		case SCF_TYPE_ASTRING:
306			len = scf_value_get_astring(val, cbuf, *bufsz);
307			if (len < 0 || len > *bufsz) {
308				ret = scf_error();
309				goto out;
310			}
311			ret = 0;
312			*bufsz = len;
313		break;
314		case SCF_TYPE_INTEGER:
315			if (scf_value_get_integer(val, &valint) != 0) {
316				ret = scf_error();
317				goto out;
318			}
319			length =  snprintf(cbuf, *bufsz, "%lld", valint);
320			if (length < 0 || length > *bufsz) {
321				ret = SA_BAD_VALUE;
322				goto out;
323			}
324			ret = 0;
325		break;
326		case SCF_TYPE_BOOLEAN:
327			if (scf_value_get_boolean(val, &bval) != 0) {
328				ret = scf_error();
329				goto out;
330			}
331			if (bval == 1) {
332				length = snprintf(cbuf, *bufsz, "%s", "true");
333			} else {
334				length = snprintf(cbuf, *bufsz, "%s", "false");
335			}
336			if (length < 0 || length > *bufsz) {
337				ret = SA_BAD_VALUE;
338				goto out;
339			}
340		break;
341		}
342	} else {
343		ret = scf_error();
344	}
345	if ((ret != 0) && scf_error() != SCF_ERROR_NONE)
346		fprintf(stdout, gettext("%s\n"), scf_strerror(ret));
347out:
348	fs_smf_fini(phandle);
349	return (ret);
350}
351
352
353int
354nfs_smf_get_prop(char *prop_name, char *propbuf, char *instance,
355    scf_type_t sctype, char *svc_name, int *bufsz)
356{
357	return (fs_smf_get_prop(NFS_SMF, prop_name, propbuf,
358	    instance, sctype, svc_name, bufsz));
359}
360
361int
362nfs_smf_set_prop(char *prop_name, char *value, char *instance,
363    scf_type_t type, char *svc_name)
364{
365	return (fs_smf_set_prop(NFS_SMF, prop_name, value, instance,
366	    type, svc_name));
367}
368
369int
370autofs_smf_set_prop(char *prop_name, char *value, char *instance,
371    scf_type_t type, char *svc_name)
372{
373	return (fs_smf_set_prop(AUTOFS_SMF, prop_name, value, instance,
374	    type, svc_name));
375}
376
377int
378autofs_smf_get_prop(char *prop_name, char *propbuf, char *instance,
379    scf_type_t sctype, char *svc_name, int *bufsz)
380{
381	return (fs_smf_get_prop(AUTOFS_SMF, prop_name, propbuf,
382	    instance, sctype, svc_name, bufsz));
383}
384
385boolean_t
386string_to_boolean(const char *str)
387{
388	if (strcasecmp(str, "true") == 0 || atoi(str) == 1 ||
389	    strcasecmp(str, "on") == 0 || strcasecmp(str, "yes") == 0) {
390		return (B_TRUE);
391	} else
392		return (B_FALSE);
393}
394