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 }