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 { NULL } 234 }; 235 scf_propvec_t *prop; 236 237 rc = scf_fmri_pg_get_or_add(FMRI_BOOT_CONFIG, 238 BOOT_CONFIG_PG_OVR, SCF_GROUP_APPLICATION, 239 SCF_PG_FLAG_NONPERSISTENT, set); 240 241 if (rc != SCF_SUCCESS) { 242 #if defined(FASTREBOOT_DEBUG) 243 if (set) 244 (void) uu_warn("Unable to add service %s " 245 "property group '%s'\n", 246 FMRI_BOOT_CONFIG, BOOT_CONFIG_PG_OVR); 247 #endif /* FASTREBOOT_DEBUG */ 248 return (rc); 249 } 250 251 for (prop = ua_boot_config_ovr; prop->pv_prop != NULL; prop++) 252 prop->pv_ptr = boot_config_ovr; 253 prop = NULL; 254 255 if (set) 256 rc = scf_write_propvec(FMRI_BOOT_CONFIG, 257 BOOT_CONFIG_PG_OVR, ua_boot_config_ovr, &prop); 258 else 259 rc = scf_read_propvec(FMRI_BOOT_CONFIG, 260 BOOT_CONFIG_PG_OVR, B_FALSE, ua_boot_config_ovr, 261 &prop); 262 263 #if defined(FASTREBOOT_DEBUG) 264 if (rc != SCF_SUCCESS) { 265 if (prop != NULL) { 266 (void) uu_warn("Service %s property '%s/%s' " 267 "not found.\n", FMRI_BOOT_CONFIG, 268 BOOT_CONFIG_PG_OVR, prop->pv_prop); 269 } else { 270 (void) uu_warn("Unable to %s service %s " 271 "property '%s': %s\n", set ? "set" : "get", 272 FMRI_BOOT_CONFIG, BOOT_CONFIG_PG_OVR, 273 scf_strerror(scf_error())); 274 } 275 } 276 #endif /* FASTREBOOT_DEBUG */ 277 return (rc); 278 279 } 280 #endif /* __x86 */ 281 } 282 283 /* 284 * Get values of properties in non-persistent "config_ovr" property group. 285 */ 286 static void 287 scf_get_boot_config_ovr(uint8_t *boot_config_ovr) 288 { 289 (void) scf_getset_boot_config_ovr(B_FALSE, boot_config_ovr); 290 } 291 292 /* 293 * Set value of "config_ovr/fastreboot_default". 294 */ 295 int 296 scf_fastreboot_default_set_transient(boolean_t value) 297 { 298 uint8_t boot_config_ovr = (value & UA_FASTREBOOT_DEFAULT); 299 300 return (scf_getset_boot_config_ovr(B_TRUE, &boot_config_ovr)); 301 } 302 303 /* 304 * Check whether Fast Reboot is the default operating mode. 305 * Return 0 if 306 * 1. the platform is xVM 307 * or 308 * 2. svc:/system/boot-config:default service doesn't exist, 309 * or 310 * 3. property "config/fastreboot_default" doesn't exist, 311 * or 312 * 4. value of property "config/fastreboot_default" is set to "false" 313 * and "config_ovr/fastreboot_default" is not set to "true", 314 * or 315 * 5. the platform has been blacklisted. 316 * or 317 * 6. value of property "config_ovr/fastreboot_default" is set to "false". 318 * Return non-zero otherwise. 319 */ 320 int 321 scf_is_fastboot_default(void) 322 { 323 uint8_t boot_config = 0, boot_config_ovr; 324 char procbuf[SYS_NMLN]; 325 326 /* 327 * If we are on xVM, do not fast reboot by default. 328 */ 329 if (sysinfo(SI_PLATFORM, procbuf, sizeof (procbuf)) == -1 || 330 strcmp(procbuf, "i86xpv") == 0) 331 return (0); 332 333 /* 334 * Get property values from "config" property group 335 */ 336 scf_get_boot_config(&boot_config); 337 338 /* 339 * Get property values from non-persistent "config_ovr" property group 340 */ 341 boot_config_ovr = boot_config; 342 scf_get_boot_config_ovr(&boot_config_ovr); 343 344 return (boot_config & boot_config_ovr & UA_FASTREBOOT_DEFAULT); 345 } 346