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 assert(boot_config); 163 *boot_config = 0; 164 165 { 166 /* 167 * Property vector for BOOT_CONFIG_PG_PARAMS property group. 168 */ 169 scf_propvec_t ua_boot_config[] = { 170 { FASTREBOOT_DEFAULT, NULL, SCF_TYPE_BOOLEAN, NULL, 171 UA_FASTREBOOT_DEFAULT }, 172 { FASTREBOOT_ONPANIC, NULL, SCF_TYPE_BOOLEAN, NULL, 173 UA_FASTREBOOT_ONPANIC }, 174 { NULL } 175 }; 176 scf_propvec_t *prop; 177 178 for (prop = ua_boot_config; prop->pv_prop != NULL; prop++) 179 prop->pv_ptr = boot_config; 180 prop = NULL; 181 if (scf_read_propvec(FMRI_BOOT_CONFIG, BOOT_CONFIG_PG_PARAMS, 182 B_TRUE, ua_boot_config, &prop) != SCF_FAILED) { 183 184 #ifdef __x86 185 /* 186 * Unset both flags if the platform has been 187 * blacklisted. 188 */ 189 if (scf_is_fb_blacklisted()) 190 *boot_config &= ~(UA_FASTREBOOT_DEFAULT | 191 UA_FASTREBOOT_ONPANIC); 192 #endif /* __x86 */ 193 return; 194 } 195 #if defined(FASTREBOOT_DEBUG) 196 if (prop != NULL) { 197 (void) uu_warn("Service %s property '%s/%s' " 198 "not found.\n", FMRI_BOOT_CONFIG, 199 BOOT_CONFIG_PG_PARAMS, prop->pv_prop); 200 } else { 201 (void) uu_warn("Unable to read service %s " 202 "property '%s': %s\n", FMRI_BOOT_CONFIG, 203 BOOT_CONFIG_PG_PARAMS, scf_strerror(scf_error())); 204 } 205 #endif /* FASTREBOOT_DEBUG */ 206 } 207 } 208 209 /* 210 * Get or set properties in non-persistent "config_ovr" property group 211 * in svc:/system/boot-config:default. 212 * It prints errors with uu_warn(). 213 */ 214 /*ARGSUSED*/ 215 static int 216 scf_getset_boot_config_ovr(int set, uint8_t *boot_config_ovr) 217 { 218 int rc = SCF_SUCCESS; 219 220 assert(boot_config_ovr); 221 222 #ifndef __x86 223 return (rc); 224 #else 225 { 226 /* 227 * Property vector for BOOT_CONFIG_PG_OVR property group. 228 */ 229 scf_propvec_t ua_boot_config_ovr[] = { 230 { FASTREBOOT_DEFAULT, NULL, SCF_TYPE_BOOLEAN, NULL, 231 UA_FASTREBOOT_DEFAULT }, 232 { FASTREBOOT_ONPANIC, NULL, SCF_TYPE_BOOLEAN, NULL, 233 UA_FASTREBOOT_ONPANIC }, 234 { NULL } 235 }; 236 scf_propvec_t *prop; 237 238 rc = scf_fmri_pg_get_or_add(FMRI_BOOT_CONFIG, 239 BOOT_CONFIG_PG_OVR, SCF_GROUP_APPLICATION, 240 SCF_PG_FLAG_NONPERSISTENT, set); 241 242 if (rc != SCF_SUCCESS) { 243 #if defined(FASTREBOOT_DEBUG) 244 if (set) 245 (void) uu_warn("Unable to add service %s " 246 "property group '%s'\n", 247 FMRI_BOOT_CONFIG, BOOT_CONFIG_PG_OVR); 248 #endif /* FASTREBOOT_DEBUG */ 249 return (rc); 250 } 251 252 for (prop = ua_boot_config_ovr; prop->pv_prop != NULL; prop++) 253 prop->pv_ptr = boot_config_ovr; 254 prop = NULL; 255 256 if (set) 257 rc = scf_write_propvec(FMRI_BOOT_CONFIG, 258 BOOT_CONFIG_PG_OVR, ua_boot_config_ovr, &prop); 259 else 260 rc = scf_read_propvec(FMRI_BOOT_CONFIG, 261 BOOT_CONFIG_PG_OVR, B_FALSE, ua_boot_config_ovr, 262 &prop); 263 264 #if defined(FASTREBOOT_DEBUG) 265 if (rc != SCF_SUCCESS) { 266 if (prop != NULL) { 267 (void) uu_warn("Service %s property '%s/%s' " 268 "not found.\n", FMRI_BOOT_CONFIG, 269 BOOT_CONFIG_PG_OVR, prop->pv_prop); 270 } else { 271 (void) uu_warn("Unable to %s service %s " 272 "property '%s': %s\n", set ? "set" : "get", 273 FMRI_BOOT_CONFIG, BOOT_CONFIG_PG_OVR, 274 scf_strerror(scf_error())); 275 } 276 } 277 #endif /* FASTREBOOT_DEBUG */ 278 279 if (set) 280 (void) smf_refresh_instance(FMRI_BOOT_CONFIG); 281 282 return (rc); 283 284 } 285 #endif /* __x86 */ 286 } 287 288 /* 289 * Get values of properties in non-persistent "config_ovr" property group. 290 */ 291 void 292 scf_get_boot_config_ovr(uint8_t *boot_config_ovr) 293 { 294 (void) scf_getset_boot_config_ovr(B_FALSE, boot_config_ovr); 295 } 296 297 /* 298 * Set value of "config_ovr/fastreboot_default". 299 */ 300 int 301 scf_fastreboot_default_set_transient(boolean_t value) 302 { 303 uint8_t boot_config_ovr = 0; 304 305 if (value == B_TRUE) 306 boot_config_ovr = UA_FASTREBOOT_DEFAULT | UA_FASTREBOOT_ONPANIC; 307 308 return (scf_getset_boot_config_ovr(B_TRUE, &boot_config_ovr)); 309 } 310 311 /* 312 * Check whether Fast Reboot is the default operating mode. 313 * Return 0 if 314 * 1. the platform is xVM 315 * or 316 * 2. svc:/system/boot-config:default service doesn't exist, 317 * or 318 * 3. property "config/fastreboot_default" doesn't exist, 319 * or 320 * 4. value of property "config/fastreboot_default" is set to "false" 321 * and "config_ovr/fastreboot_default" is not set to "true", 322 * or 323 * 5. the platform has been blacklisted. 324 * or 325 * 6. value of property "config_ovr/fastreboot_default" is set to "false". 326 * Return non-zero otherwise. 327 */ 328 int 329 scf_is_fastboot_default(void) 330 { 331 uint8_t boot_config = 0, boot_config_ovr; 332 char procbuf[SYS_NMLN]; 333 334 /* 335 * If we are on xVM, do not fast reboot by default. 336 */ 337 if (sysinfo(SI_PLATFORM, procbuf, sizeof (procbuf)) == -1 || 338 strcmp(procbuf, "i86xpv") == 0) 339 return (0); 340 341 /* 342 * Get property values from "config" property group 343 */ 344 scf_get_boot_config(&boot_config); 345 346 /* 347 * Get property values from non-persistent "config_ovr" property group 348 */ 349 boot_config_ovr = boot_config; 350 scf_get_boot_config_ovr(&boot_config_ovr); 351 352 return (boot_config & boot_config_ovr & UA_FASTREBOOT_DEFAULT); 353 } 354