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