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