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