xref: /illumos-gate/usr/src/cmd/fs.d/nfs/lib/smfcfg.c (revision 101e15b5f8a77d9433805e541996abaabc9ca8c1)
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 <rpcsvc/daemon_utils.h>
33 #include "smfcfg.h"
34 
35 fs_smfhandle_t *
36 fs_smf_init(const char *fmri, const char *instance)
37 {
38 	fs_smfhandle_t *handle = NULL;
39 	char *svcname, srv[MAXPATHLEN];
40 
41 	/*
42 	 * svc name is of the form svc://network/fs/server:instance1
43 	 * FMRI portion is /network/fs/server
44 	 */
45 	(void) snprintf(srv, MAXPATHLEN, "%s", fmri + strlen("svc:/"));
46 	svcname = strrchr(srv, ':');
47 	if (svcname != NULL)
48 		*svcname = '\0';
49 	svcname = srv;
50 
51 	handle = calloc(1, sizeof (fs_smfhandle_t));
52 	if (handle != NULL) {
53 		handle->fs_handle = scf_handle_create(SCF_VERSION);
54 		if (handle->fs_handle == NULL)
55 			goto out;
56 		if (scf_handle_bind(handle->fs_handle) != 0)
57 			goto out;
58 		handle->fs_service =
59 		    scf_service_create(handle->fs_handle);
60 		handle->fs_scope =
61 		    scf_scope_create(handle->fs_handle);
62 		if (scf_handle_get_local_scope(handle->fs_handle,
63 		    handle->fs_scope) != 0)
64 			goto out;
65 		if (scf_scope_get_service(handle->fs_scope,
66 		    svcname, handle->fs_service)  != SCF_SUCCESS) {
67 			goto out;
68 		}
69 		handle->fs_pg =
70 		    scf_pg_create(handle->fs_handle);
71 		handle->fs_instance =
72 		    scf_instance_create(handle->fs_handle);
73 		handle->fs_property =
74 		    scf_property_create(handle->fs_handle);
75 		handle->fs_value =
76 		    scf_value_create(handle->fs_handle);
77 	} else {
78 		fprintf(stderr,
79 		    gettext("Cannot access SMF repository: %s\n"), fmri);
80 	}
81 	return (handle);
82 
83 out:
84 	fs_smf_fini(handle);
85 	if (scf_error() != SCF_ERROR_NOT_FOUND) {
86 		fprintf(stderr,
87 		    gettext("SMF Initialization problem(%s): %s\n"),
88 		    fmri, scf_strerror(scf_error()));
89 	}
90 	return (NULL);
91 }
92 
93 void
94 fs_smf_fini(fs_smfhandle_t *handle)
95 {
96 	if (handle != NULL) {
97 		scf_scope_destroy(handle->fs_scope);
98 		scf_instance_destroy(handle->fs_instance);
99 		scf_service_destroy(handle->fs_service);
100 		scf_pg_destroy(handle->fs_pg);
101 		scf_property_destroy(handle->fs_property);
102 		scf_value_destroy(handle->fs_value);
103 		if (handle->fs_handle != NULL) {
104 			(void) scf_handle_unbind(handle->fs_handle);
105 			scf_handle_destroy(handle->fs_handle);
106 		}
107 		free(handle);
108 	}
109 }
110 
111 int
112 fs_smf_set_prop(smf_fstype_t fstype, char *prop_name, char *valbuf,
113     char *instance, scf_type_t sctype, char *fmri)
114 {
115 	fs_smfhandle_t *phandle = NULL;
116 	scf_handle_t *handle;
117 	scf_propertygroup_t *pg;
118 	scf_property_t *prop;
119 	scf_transaction_t *tran = NULL;
120 	scf_transaction_entry_t *entry = NULL;
121 	scf_instance_t *inst;
122 	scf_value_t *val;
123 	int valint;
124 	int ret = 0;
125 	char *p = NULL;
126 	char *svcname, srv[MAXPATHLEN];
127 	const char *pgname;
128 
129 	/*
130 	 * The SVC names we are using currently are already
131 	 * appended by default. Fix this for instances project.
132 	 */
133 	(void) snprintf(srv, MAXPATHLEN, "%s", fmri);
134 	p = strstr(fmri, ":default");
135 	if (p == NULL) {
136 		(void) strcat(srv, ":");
137 		if (instance == NULL)
138 			instance = "default";
139 		if (strlen(srv) + strlen(instance) > MAXPATHLEN)
140 			goto out;
141 		(void) strncat(srv, instance, strlen(instance));
142 	}
143 	svcname = srv;
144 	phandle = fs_smf_init(fmri, instance);
145 	if (phandle == NULL) {
146 		return (SMF_SYSTEM_ERR);
147 	}
148 	handle = phandle->fs_handle;
149 	pg = phandle->fs_pg;
150 	prop = phandle->fs_property;
151 	inst = phandle->fs_instance;
152 	val = phandle->fs_value;
153 	tran = scf_transaction_create(handle);
154 	entry = scf_entry_create(handle);
155 
156 	if (handle == NULL || pg == NULL || prop == NULL ||
157 	    val == NULL|| tran == NULL || entry == NULL || inst == NULL) {
158 		ret = SMF_SYSTEM_ERR;
159 		goto out;
160 	}
161 
162 	if (scf_handle_decode_fmri(handle, svcname, phandle->fs_scope,
163 	    phandle->fs_service, inst, NULL, NULL, 0) != 0) {
164 		ret = scf_error();
165 		goto out;
166 	}
167 	if (fstype == AUTOFS_SMF)
168 		pgname = AUTOFS_PROPS_PGNAME;
169 	else
170 		pgname = NFS_PROPS_PGNAME;
171 
172 	if (scf_instance_get_pg(inst, pgname,
173 	    pg) != -1) {
174 		uint8_t	vint;
175 		if (scf_transaction_start(tran, pg) == -1) {
176 			ret = scf_error();
177 			goto out;
178 		}
179 		switch (sctype) {
180 		case SCF_TYPE_INTEGER:
181 			errno = 0;
182 			valint = strtoul(valbuf, NULL, 0);
183 			if (errno != 0) {
184 				ret = SMF_SYSTEM_ERR;
185 				goto out;
186 			}
187 			if (scf_transaction_property_change(tran,
188 			    entry, prop_name, SCF_TYPE_INTEGER) == 0) {
189 				scf_value_set_integer(val, valint);
190 				if (scf_entry_add_value(entry, val) < 0) {
191 					ret = scf_error();
192 					goto out;
193 				}
194 			}
195 			break;
196 		case SCF_TYPE_ASTRING:
197 			if (scf_transaction_property_change(tran, entry,
198 			    prop_name, SCF_TYPE_ASTRING) == 0) {
199 				if (scf_value_set_astring(val,
200 				    valbuf) == 0) {
201 					if (scf_entry_add_value(entry,
202 					    val) != 0) {
203 						ret = scf_error();
204 						goto out;
205 					}
206 				} else
207 					ret = SMF_SYSTEM_ERR;
208 			} else
209 				ret = SMF_SYSTEM_ERR;
210 			break;
211 		case SCF_TYPE_BOOLEAN:
212 			if (strcmp(valbuf, "1") == 0) {
213 				vint = 1;
214 			} else if (strcmp(valbuf, "0") == 0) {
215 				vint = 0;
216 			} else  {
217 				ret = SMF_SYSTEM_ERR;
218 				break;
219 			}
220 			if (scf_transaction_property_change(tran, entry,
221 			    prop_name, SCF_TYPE_BOOLEAN) == 0) {
222 				scf_value_set_boolean(val, (uint8_t)vint);
223 				if (scf_entry_add_value(entry, val) != 0) {
224 					ret = scf_error();
225 					goto out;
226 				}
227 			} else {
228 				ret = SMF_SYSTEM_ERR;
229 			}
230 			break;
231 		default:
232 			break;
233 		}
234 		if (ret != SMF_SYSTEM_ERR)
235 			(void) scf_transaction_commit(tran);
236 	}
237 out:
238 	if (tran != NULL)
239 		scf_transaction_destroy(tran);
240 	if (entry != NULL)
241 		scf_entry_destroy(entry);
242 	fs_smf_fini(phandle);
243 	return (ret);
244 }
245 
246 int
247 fs_smf_get_prop(smf_fstype_t fstype, char *prop_name, char *cbuf,
248     char *instance, scf_type_t sctype, char *fmri, int *bufsz)
249 {
250 	fs_smfhandle_t *phandle = NULL;
251 	scf_handle_t *handle;
252 	scf_propertygroup_t *pg;
253 	scf_property_t *prop;
254 	scf_value_t *val;
255 	scf_instance_t *inst;
256 	int ret = 0, len = 0, length;
257 	int64_t valint = 0;
258 	char srv[MAXPATHLEN], *p, *svcname;
259 	const char *pgname;
260 	uint8_t bval;
261 
262 	/*
263 	 * The SVC names we are using currently are already
264 	 * appended by default. Fix this for instances project.
265 	 */
266 	(void) snprintf(srv, MAXPATHLEN, "%s", fmri);
267 	p = strstr(fmri, ":default");
268 	if (p == NULL) {
269 		(void) strcat(srv, ":");
270 		if (instance == NULL)
271 			instance = "default";
272 		if (strlen(srv) + strlen(instance) > MAXPATHLEN)
273 			goto out;
274 		(void) strncat(srv, instance, strlen(instance));
275 	}
276 	svcname = srv;
277 	phandle = fs_smf_init(fmri, instance);
278 	if (phandle == NULL)
279 		return (SMF_SYSTEM_ERR);
280 	handle = phandle->fs_handle;
281 	pg = phandle->fs_pg;
282 	inst = phandle->fs_instance;
283 	prop = phandle->fs_property;
284 	val = phandle->fs_value;
285 
286 	if (handle == NULL || pg == NULL || prop == NULL || val == NULL ||
287 	    inst == NULL)  {
288 		return (SMF_SYSTEM_ERR);
289 	}
290 
291 
292 	if (scf_handle_decode_fmri(handle, svcname, phandle->fs_scope,
293 	    phandle->fs_service, inst, NULL, NULL, 0) != 0) {
294 		ret = scf_error();
295 		goto out;
296 	}
297 
298 	if (fstype == AUTOFS_SMF)
299 		pgname = AUTOFS_PROPS_PGNAME;
300 	else
301 		pgname = NFS_PROPS_PGNAME;
302 
303 	if (scf_instance_get_pg(inst, pgname, pg) != -1) {
304 		if (scf_pg_get_property(pg, prop_name,
305 		    prop) != SCF_SUCCESS) {
306 			ret = scf_error();
307 			goto out;
308 		}
309 		if (scf_property_get_value(prop, val) != SCF_SUCCESS) {
310 			ret = scf_error();
311 			goto out;
312 		}
313 		switch (sctype) {
314 		case SCF_TYPE_ASTRING:
315 			len = scf_value_get_astring(val, cbuf, *bufsz);
316 			if (len < 0 || len > *bufsz) {
317 				ret = scf_error();
318 				goto out;
319 			}
320 			ret = 0;
321 			*bufsz = len;
322 			break;
323 		case SCF_TYPE_INTEGER:
324 			if (scf_value_get_integer(val, &valint) != 0) {
325 				ret = scf_error();
326 				goto out;
327 			}
328 			length =  snprintf(cbuf, *bufsz, "%lld", valint);
329 			if (length < 0 || length > *bufsz) {
330 				ret = SA_BAD_VALUE;
331 				goto out;
332 			}
333 			ret = 0;
334 			break;
335 		case SCF_TYPE_BOOLEAN:
336 			if (scf_value_get_boolean(val, &bval) != 0) {
337 				ret = scf_error();
338 				goto out;
339 			}
340 			if (bval == 1) {
341 				length = snprintf(cbuf, *bufsz, "%s", "true");
342 			} else {
343 				length = snprintf(cbuf, *bufsz, "%s", "false");
344 			}
345 			if (length < 0 || length > *bufsz) {
346 				ret = SA_BAD_VALUE;
347 				goto out;
348 			}
349 			break;
350 		default:
351 			break;
352 		}
353 	} else {
354 		ret = scf_error();
355 	}
356 	if ((ret != 0) && scf_error() != SCF_ERROR_NONE)
357 		fprintf(stdout, gettext("%s\n"), scf_strerror(ret));
358 out:
359 	fs_smf_fini(phandle);
360 	return (ret);
361 }
362 
363 
364 int
365 nfs_smf_get_prop(char *prop_name, char *propbuf, char *instance,
366     scf_type_t sctype, char *svc_name, int *bufsz)
367 {
368 	return (fs_smf_get_prop(NFS_SMF, prop_name, propbuf,
369 	    instance, sctype, svc_name, bufsz));
370 }
371 
372 /* Get an integer (base 10) property */
373 int
374 nfs_smf_get_iprop(char *prop_name, int *rvp, char *instance,
375     scf_type_t sctype, char *svc_name)
376 {
377 	char propbuf[32];
378 	int bufsz, rc, val;
379 
380 	bufsz = sizeof (propbuf);
381 	rc = fs_smf_get_prop(NFS_SMF, prop_name, propbuf,
382 	    instance, sctype, svc_name, &bufsz);
383 	if (rc != SA_OK)
384 		return (rc);
385 	errno = 0;
386 	val = strtol(propbuf, NULL, 10);
387 	if (errno != 0)
388 		return (SA_BAD_VALUE);
389 	*rvp = val;
390 	return (SA_OK);
391 }
392 
393 int
394 nfs_smf_set_prop(char *prop_name, char *value, char *instance,
395     scf_type_t type, char *svc_name)
396 {
397 	return (fs_smf_set_prop(NFS_SMF, prop_name, value, instance,
398 	    type, svc_name));
399 }
400 
401 int
402 autofs_smf_set_prop(char *prop_name, char *value, char *instance,
403     scf_type_t type, char *svc_name)
404 {
405 	return (fs_smf_set_prop(AUTOFS_SMF, prop_name, value, instance,
406 	    type, svc_name));
407 }
408 
409 int
410 autofs_smf_get_prop(char *prop_name, char *propbuf, char *instance,
411     scf_type_t sctype, char *svc_name, int *bufsz)
412 {
413 	return (fs_smf_get_prop(AUTOFS_SMF, prop_name, propbuf,
414 	    instance, sctype, svc_name, bufsz));
415 }
416 
417 boolean_t
418 string_to_boolean(const char *str)
419 {
420 	if (strcasecmp(str, "true") == 0 || atoi(str) == 1 ||
421 	    strcasecmp(str, "on") == 0 || strcasecmp(str, "yes") == 0) {
422 		return (B_TRUE);
423 	} else
424 		return (B_FALSE);
425 }
426 
427 /*
428  * upgrade server_versmin and server_versmax from int to string.
429  * This is needed to allow to specify version as major.minor.
430  */
431 static void
432 nfs_upgrade_server_vers(const char *fmri)
433 {
434 	fs_smfhandle_t *phandle;
435 	scf_handle_t *handle;
436 	scf_propertygroup_t *pg;
437 	scf_instance_t *inst;
438 	scf_value_t *vmin = NULL, *vmax = NULL;
439 	scf_transaction_t *tran = NULL;
440 	scf_transaction_entry_t *emin = NULL, *emax = NULL;
441 	char versmax[32];
442 	char versmin[32];
443 	int bufsz;
444 
445 	/*
446 	 * Read old integer values, stop in case of error - apparently
447 	 * the upgrade is already done.
448 	 */
449 	bufsz = sizeof (versmax);
450 	if (nfs_smf_get_prop("server_versmax", versmax, DEFAULT_INSTANCE,
451 	    SCF_TYPE_INTEGER, (char *)fmri, &bufsz) != SA_OK) {
452 		return;
453 	}
454 	bufsz = sizeof (versmin);
455 	if (nfs_smf_get_prop("server_versmin", versmin, DEFAULT_INSTANCE,
456 	    SCF_TYPE_INTEGER, (char *)fmri, &bufsz) != SA_OK) {
457 		return;
458 	}
459 
460 	/* Write back as SCF_TYPE_ASTRING */
461 	phandle = fs_smf_init(fmri, NULL);
462 	if (phandle == NULL)
463 		return;
464 
465 	handle = phandle->fs_handle;
466 	if (handle == NULL)
467 		goto done;
468 	pg = phandle->fs_pg;
469 	inst = phandle->fs_instance;
470 	tran = scf_transaction_create(handle);
471 	vmin = scf_value_create(handle);
472 	vmax = scf_value_create(handle);
473 	emin = scf_entry_create(handle);
474 	emax = scf_entry_create(handle);
475 
476 	if (pg == NULL || inst == NULL || tran == NULL ||
477 	    emin == NULL || emax == NULL || vmin == NULL || vmax == NULL) {
478 		goto done;
479 	}
480 
481 	if (scf_handle_decode_fmri(handle, (char *)fmri,
482 	    phandle->fs_scope, phandle->fs_service, inst, NULL, NULL, 0) != 0) {
483 		goto done;
484 	}
485 
486 	if (scf_instance_get_pg(inst, NFS_PROPS_PGNAME, pg) == -1)
487 		goto done;
488 
489 	if (scf_pg_update(pg) == -1)
490 		goto done;
491 
492 	if (scf_transaction_start(tran, pg) == -1)
493 		goto done;
494 
495 	if (scf_transaction_property_change_type(tran, emax,
496 	    "server_versmax", SCF_TYPE_ASTRING) != 0) {
497 		goto done;
498 	}
499 	if (scf_value_set_astring(vmax, versmax) == 0) {
500 		if (scf_entry_add_value(emax, vmax) != 0)
501 			goto done;
502 	} else {
503 		goto done;
504 	}
505 
506 	if (scf_transaction_property_change_type(tran, emin,
507 	    "server_versmin", SCF_TYPE_ASTRING) != 0) {
508 		goto done;
509 	}
510 	if (scf_value_set_astring(vmin, versmin) == 0) {
511 		if (scf_entry_add_value(emin, vmin) != 0)
512 			goto done;
513 	} else {
514 		goto done;
515 	}
516 
517 	(void) scf_transaction_commit(tran);
518 done:
519 	if (tran != NULL)
520 		scf_transaction_destroy(tran);
521 	if (emin != NULL)
522 		scf_entry_destroy(emin);
523 	if (emax != NULL)
524 		scf_entry_destroy(emax);
525 	if (vmin != NULL)
526 		scf_value_destroy(vmin);
527 	if (vmax != NULL)
528 		scf_value_destroy(vmax);
529 	fs_smf_fini(phandle);
530 }
531 
532 void
533 nfs_config_upgrade(const char *svc_name)
534 {
535 	if (strcmp(svc_name, NFSD) == 0) {
536 		nfs_upgrade_server_vers(svc_name);
537 	}
538 }
539