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 2010 Sun Microsystems, Inc.  All rights reserved.
  24  * Use is subject to license terms.
  25  */
  26 
  27 /*
  28  * This file contains high level functions used by multiple utilities.
  29  */
  30 
  31 #include "libscf_impl.h"
  32 
  33 #include <assert.h>
  34 #include <libuutil.h>
  35 #include <string.h>
  36 #include <stdlib.h>
  37 #include <sys/systeminfo.h>
  38 #include <sys/uadmin.h>
  39 #include <sys/utsname.h>
  40 
  41 #ifdef  __x86
  42 #include <smbios.h>
  43 
  44 /*
  45  * Check whether the platform is on the fastreboot_blacklist.
  46  * Return 1 if the platform has been blacklisted, 0 otherwise.
  47  */
  48 static int
  49 scf_is_fb_blacklisted(void)
  50 {
  51         smbios_hdl_t *shp;
  52         smbios_system_t sys;
  53         smbios_info_t info;
  54 
  55         id_t id;
  56         int err;
  57         int i;
  58 
  59         scf_simple_prop_t *prop = NULL;
  60         ssize_t numvals;
  61         char *platform_name;
  62 
  63         int blacklisted = 0;
  64 
  65         /*
  66          * If there's no SMBIOS, assume it's blacklisted.
  67          */
  68         if ((shp = smbios_open(NULL, SMB_VERSION, 0, &err)) == NULL)
  69                 return (1);
  70 
  71         /*
  72          * If we can't read system info, assume it's blacklisted.
  73          */
  74         if ((id = smbios_info_system(shp, &sys)) == SMB_ERR ||
  75             smbios_info_common(shp, id, &info) == SMB_ERR) {
  76                 blacklisted = 1;
  77                 goto fb_out;
  78         }
  79 
  80         /*
  81          * If we can't read the "platforms" property from property group
  82          * BOOT_CONFIG_PG_FBBLACKLIST, assume no platforms have
  83          * been blacklisted.
  84          */
  85         if ((prop = scf_simple_prop_get(NULL, FMRI_BOOT_CONFIG,
  86             BOOT_CONFIG_PG_FBBLACKLIST, "platforms")) == NULL)
  87                 goto fb_out;
  88 
  89         numvals = scf_simple_prop_numvalues(prop);
  90 
  91         for (i = 0; i < numvals; i++) {
  92                 platform_name = scf_simple_prop_next_astring(prop);
  93                 if (platform_name == NULL)
  94                         break;
  95                 if (strcmp(platform_name, info.smbi_product) == 0) {
  96                         blacklisted = 1;
  97                         break;
  98                 }
  99         }
 100 
 101 fb_out:
 102         smbios_close(shp);
 103         scf_simple_prop_free(prop);
 104 
 105         return (blacklisted);
 106 }
 107 
 108 /*
 109  * Add or get a property group given an FMRI.
 110  * Return SCF_SUCCESS on success, SCF_FAILED on failure.
 111  */
 112 static int
 113 scf_fmri_pg_get_or_add(const char *fmri, const char *pgname,
 114     const char *pgtype, uint32_t pgflags, int add)
 115 {
 116         scf_handle_t    *handle = NULL;
 117         scf_instance_t  *inst = NULL;
 118         int             rc = SCF_FAILED;
 119         int             error;
 120 
 121         if ((handle = scf_handle_create(SCF_VERSION)) == NULL ||
 122             scf_handle_bind(handle) != 0 ||
 123             (inst = scf_instance_create(handle)) == NULL ||
 124             scf_handle_decode_fmri(handle, fmri, NULL, NULL,
 125             inst, NULL, NULL, SCF_DECODE_FMRI_EXACT) != SCF_SUCCESS)
 126                 goto scferror;
 127 
 128         if (add) {
 129                 rc = scf_instance_add_pg(inst, pgname, pgtype, pgflags, NULL);
 130                 /*
 131                  * If the property group already exists, return SCF_SUCCESS.
 132                  */
 133                 if (rc != SCF_SUCCESS && scf_error() == SCF_ERROR_EXISTS)
 134                         rc = SCF_SUCCESS;
 135         } else {
 136                 rc = scf_instance_get_pg(inst, pgname, NULL);
 137         }
 138 
 139 scferror:
 140         if (rc != SCF_SUCCESS)
 141                 error = scf_error();
 142 
 143         scf_instance_destroy(inst);
 144         if (handle)
 145                 (void) scf_handle_unbind(handle);
 146         scf_handle_destroy(handle);
 147 
 148         if (rc != SCF_SUCCESS)
 149                 (void) scf_set_error(error);
 150 
 151         return (rc);
 152 }
 153 #endif  /* __x86 */
 154 
 155 /*
 156  * Get config properties from svc:/system/boot-config:default.
 157  * It prints errors with uu_warn().
 158  */
 159 void
 160 scf_get_boot_config(uint8_t *boot_config)
 161 {
 162         uint64_t ret = 0;
 163 
 164         assert(boot_config);
 165         *boot_config = 0;
 166 
 167         {
 168                 /*
 169                  * Property vector for BOOT_CONFIG_PG_PARAMS property group.
 170                  */
 171                 scf_propvec_t ua_boot_config[] = {
 172                         { FASTREBOOT_DEFAULT, NULL, SCF_TYPE_BOOLEAN, NULL,
 173                             UA_FASTREBOOT_DEFAULT },
 174                         { FASTREBOOT_ONPANIC, NULL, SCF_TYPE_BOOLEAN, NULL,
 175                             UA_FASTREBOOT_ONPANIC },
 176                         { NULL }
 177                 };
 178                 scf_propvec_t   *prop;
 179 
 180                 for (prop = ua_boot_config; prop->pv_prop != NULL; prop++)
 181                         prop->pv_ptr = &ret;
 182                 prop = NULL;
 183                 if (scf_read_propvec(FMRI_BOOT_CONFIG, BOOT_CONFIG_PG_PARAMS,
 184                     B_TRUE, ua_boot_config, &prop) != SCF_FAILED) {
 185 
 186 #ifdef  __x86
 187                         /*
 188                          * Unset both flags if the platform has been
 189                          * blacklisted.
 190                          */
 191                         if (scf_is_fb_blacklisted())
 192                                 return;
 193 #endif  /* __x86 */
 194                         *boot_config = (uint8_t)ret;
 195                         return;
 196                 }
 197 #if defined(FASTREBOOT_DEBUG)
 198                 if (prop != NULL) {
 199                         (void) uu_warn("Service %s property '%s/%s' "
 200                             "not found.\n", FMRI_BOOT_CONFIG,
 201                             BOOT_CONFIG_PG_PARAMS, prop->pv_prop);
 202                 } else {
 203                         (void) uu_warn("Unable to read service %s "
 204                             "property '%s': %s\n", FMRI_BOOT_CONFIG,
 205                             BOOT_CONFIG_PG_PARAMS, scf_strerror(scf_error()));
 206                 }
 207 #endif  /* FASTREBOOT_DEBUG */
 208         }
 209 }
 210 
 211 /*
 212  * Get or set properties in non-persistent "config_ovr" property group
 213  * in svc:/system/boot-config:default.
 214  * It prints errors with uu_warn().
 215  */
 216 /*ARGSUSED*/
 217 static int
 218 scf_getset_boot_config_ovr(int set, uint8_t *boot_config_ovr)
 219 {
 220         int rc = SCF_SUCCESS;
 221 
 222         assert(boot_config_ovr);
 223 
 224 #ifndef __x86
 225         return (rc);
 226 #else
 227         {
 228                 /*
 229                  * Property vector for BOOT_CONFIG_PG_OVR property group.
 230                  */
 231                 scf_propvec_t ua_boot_config_ovr[] = {
 232                         { FASTREBOOT_DEFAULT, NULL, SCF_TYPE_BOOLEAN, NULL,
 233                             UA_FASTREBOOT_DEFAULT },
 234                         { FASTREBOOT_ONPANIC, NULL, SCF_TYPE_BOOLEAN, NULL,
 235                             UA_FASTREBOOT_ONPANIC },
 236                         { NULL }
 237                 };
 238                 scf_propvec_t   *prop;
 239 
 240                 rc = scf_fmri_pg_get_or_add(FMRI_BOOT_CONFIG,
 241                     BOOT_CONFIG_PG_OVR, SCF_GROUP_APPLICATION,
 242                     SCF_PG_FLAG_NONPERSISTENT, set);
 243 
 244                 if (rc != SCF_SUCCESS) {
 245 #if defined(FASTREBOOT_DEBUG)
 246                         if (set)
 247                                 (void) uu_warn("Unable to add service %s "
 248                                     "property group '%s'\n",
 249                                     FMRI_BOOT_CONFIG, BOOT_CONFIG_PG_OVR);
 250 #endif  /* FASTREBOOT_DEBUG */
 251                         return (rc);
 252                 }
 253 
 254                 for (prop = ua_boot_config_ovr; prop->pv_prop != NULL; prop++)
 255                         prop->pv_ptr = boot_config_ovr;
 256                 prop = NULL;
 257 
 258                 if (set)
 259                         rc = scf_write_propvec(FMRI_BOOT_CONFIG,
 260                             BOOT_CONFIG_PG_OVR, ua_boot_config_ovr, &prop);
 261                 else
 262                         rc = scf_read_propvec(FMRI_BOOT_CONFIG,
 263                             BOOT_CONFIG_PG_OVR, B_FALSE, ua_boot_config_ovr,
 264                             &prop);
 265 
 266 #if defined(FASTREBOOT_DEBUG)
 267                 if (rc != SCF_SUCCESS) {
 268                         if (prop != NULL) {
 269                                 (void) uu_warn("Service %s property '%s/%s' "
 270                                     "not found.\n", FMRI_BOOT_CONFIG,
 271                                     BOOT_CONFIG_PG_OVR, prop->pv_prop);
 272                         } else {
 273                                 (void) uu_warn("Unable to %s service %s "
 274                                     "property '%s': %s\n", set ? "set" : "get",
 275                                     FMRI_BOOT_CONFIG, BOOT_CONFIG_PG_OVR,
 276                                     scf_strerror(scf_error()));
 277                         }
 278                 }
 279 #endif  /* FASTREBOOT_DEBUG */
 280 
 281                 if (set)
 282                         (void) smf_refresh_instance(FMRI_BOOT_CONFIG);
 283 
 284                 return (rc);
 285 
 286         }
 287 #endif  /* __x86 */
 288 }
 289 
 290 /*
 291  * Get values of properties in non-persistent "config_ovr" property group.
 292  */
 293 void
 294 scf_get_boot_config_ovr(uint8_t *boot_config_ovr)
 295 {
 296         (void) scf_getset_boot_config_ovr(B_FALSE, boot_config_ovr);
 297 }
 298 
 299 /*
 300  * Set value of "config_ovr/fastreboot_default".
 301  */
 302 int
 303 scf_fastreboot_default_set_transient(boolean_t value)
 304 {
 305         uint8_t boot_config_ovr = 0;
 306 
 307         if (value == B_TRUE)
 308                 boot_config_ovr = UA_FASTREBOOT_DEFAULT | UA_FASTREBOOT_ONPANIC;
 309 
 310         return (scf_getset_boot_config_ovr(B_TRUE, &boot_config_ovr));
 311 }
 312 
 313 /*
 314  * Check whether Fast Reboot is the default operating mode.
 315  * Return 0 if
 316  *   1. the platform is xVM
 317  * or
 318  *   2. svc:/system/boot-config:default service doesn't exist,
 319  * or
 320  *   3. property "config/fastreboot_default" doesn't exist,
 321  * or
 322  *   4. value of property "config/fastreboot_default" is set to "false"
 323  *      and "config_ovr/fastreboot_default" is not set to "true",
 324  * or
 325  *   5. the platform has been blacklisted.
 326  * or
 327  *   6. value of property "config_ovr/fastreboot_default" is set to "false".
 328  * Return non-zero otherwise.
 329  */
 330 int
 331 scf_is_fastboot_default(void)
 332 {
 333         uint8_t boot_config = 0, boot_config_ovr;
 334         char procbuf[SYS_NMLN];
 335 
 336         /*
 337          * If we are on xVM, do not fast reboot by default.
 338          */
 339         if (sysinfo(SI_PLATFORM, procbuf, sizeof (procbuf)) == -1 ||
 340             strcmp(procbuf, "i86xpv") == 0)
 341                 return (0);
 342 
 343         /*
 344          * Get property values from "config" property group
 345          */
 346         scf_get_boot_config(&boot_config);
 347 
 348         /*
 349          * Get property values from non-persistent "config_ovr" property group
 350          */
 351         boot_config_ovr = boot_config;
 352         scf_get_boot_config_ovr(&boot_config_ovr);
 353 
 354         return (boot_config & boot_config_ovr & UA_FASTREBOOT_DEFAULT);
 355 }