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