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