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 = SCF_ERROR_NONE; 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 (void) scf_set_error(SCF_ERROR_NONE); 135 rc = SCF_SUCCESS; 136 } 137 } else { 138 rc = scf_instance_get_pg(inst, pgname, NULL); 139 } 140 141 scferror: 142 error = scf_error(); 143 144 scf_instance_destroy(inst); 145 if (handle) 146 (void) scf_handle_unbind(handle); 147 scf_handle_destroy(handle); 148 149 if (error != SCF_ERROR_NONE) { 150 (void) scf_set_error(error); 151 rc = SCF_FAILED; 152 } 153 return (rc); 154 } 155 #endif /* __x86 */ 156 157 /* 158 * Get config properties from svc:/system/boot-config:default. 159 * It prints errors with uu_warn(). 160 */ 161 void 162 scf_get_boot_config(uint8_t *boot_config) 163 { 164 assert(boot_config); 165 *boot_config = 0; 166 167 #ifndef __x86 168 return; 169 #else 170 { 171 /* 172 * Property vector for BOOT_CONFIG_PG_PARAMS property group. 173 */ 174 scf_propvec_t ua_boot_config[] = { 175 { FASTREBOOT_DEFAULT, NULL, SCF_TYPE_BOOLEAN, NULL, 176 UA_FASTREBOOT_DEFAULT }, 177 { FASTREBOOT_ONPANIC, NULL, SCF_TYPE_BOOLEAN, NULL, 178 UA_FASTREBOOT_ONPANIC }, 179 { NULL } 180 }; 181 scf_propvec_t *prop; 182 183 for (prop = ua_boot_config; prop->pv_prop != NULL; prop++) 184 prop->pv_ptr = boot_config; 185 prop = NULL; 186 if (scf_read_propvec(FMRI_BOOT_CONFIG, BOOT_CONFIG_PG_PARAMS, 187 B_TRUE, ua_boot_config, &prop) != SCF_FAILED) { 188 /* 189 * Unset both flags if the platform has been 190 * blacklisted. 191 */ 192 if (scf_is_fb_blacklisted()) 193 *boot_config &= ~(UA_FASTREBOOT_DEFAULT | 194 UA_FASTREBOOT_ONPANIC); 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 #endif /* __x86 */ 210 } 211 212 /* 213 * Get or set properties in non-persistent "config_ovr" property group 214 * in svc:/system/boot-config:default. 215 * It prints errors with uu_warn(). 216 */ 217 /*ARGSUSED*/ 218 static int 219 scf_getset_boot_config_ovr(int set, uint8_t *boot_config_ovr) 220 { 221 int rc = SCF_SUCCESS; 222 223 assert(boot_config_ovr); 224 225 #ifndef __x86 226 return (rc); 227 #else 228 { 229 /* 230 * Property vector for BOOT_CONFIG_PG_OVR property group. 231 */ 232 scf_propvec_t ua_boot_config_ovr[] = { 233 { FASTREBOOT_DEFAULT, NULL, SCF_TYPE_BOOLEAN, NULL, 234 UA_FASTREBOOT_DEFAULT }, 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 return (rc); 280 281 } 282 #endif /* __x86 */ 283 } 284 285 /* 286 * Get values of properties in non-persistent "config_ovr" property group. 287 */ 288 static void 289 scf_get_boot_config_ovr(uint8_t *boot_config_ovr) 290 { 291 (void) scf_getset_boot_config_ovr(B_FALSE, boot_config_ovr); 292 } 293 294 /* 295 * Set value of "config_ovr/fastreboot_default". 296 */ 297 int 298 scf_fastreboot_default_set_transient(boolean_t value) 299 { 300 uint8_t boot_config_ovr = (value & UA_FASTREBOOT_DEFAULT); 301 302 return (scf_getset_boot_config_ovr(B_TRUE, &boot_config_ovr)); 303 } 304 305 /* 306 * Check whether Fast Reboot is the default operating mode. 307 * Return 0 if 308 * 1. the platform is xVM 309 * or 310 * 2. svc:/system/boot-config:default service doesn't exist, 311 * or 312 * 3. property "config/fastreboot_default" doesn't exist, 313 * or 314 * 4. value of property "config/fastreboot_default" is set to "false" 315 * and "config_ovr/fastreboot_default" is not set to "true", 316 * or 317 * 5. the platform has been blacklisted. 318 * or 319 * 6. value of property "config_ovr/fastreboot_default" is set to "false". 320 * Return non-zero otherwise. 321 */ 322 int 323 scf_is_fastboot_default(void) 324 { 325 uint8_t boot_config = 0, boot_config_ovr; 326 char procbuf[SYS_NMLN]; 327 328 /* 329 * If we are on xVM, do not fast reboot by default. 330 */ 331 if (sysinfo(SI_PLATFORM, procbuf, sizeof (procbuf)) == -1 || 332 strcmp(procbuf, "i86xpv") == 0) 333 return (0); 334 335 /* 336 * Get property values from "config" property group 337 */ 338 scf_get_boot_config(&boot_config); 339 340 /* 341 * Get property values from non-persistent "config_ovr" property group 342 */ 343 boot_config_ovr = boot_config; 344 scf_get_boot_config_ovr(&boot_config_ovr); 345 346 return (boot_config & boot_config_ovr & UA_FASTREBOOT_DEFAULT); 347 } 348