1/* 2 * Copyright (c) 2011 Apple Inc. All rights reserved. 3 * 4 * @APPLE_LICENSE_HEADER_START@ 5 * 6 * This file contains Original Code and/or Modifications of Original Code 7 * as defined in and that are subject to the Apple Public Source License 8 * Version 2.0 (the 'License'). You may not use this file except in 9 * compliance with the License. Please obtain a copy of the License at 10 * http://www.opensource.apple.com/apsl/ and read it before using this 11 * file. 12 * 13 * The Original Code and all software distributed under the License are 14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 18 * Please see the License for the specific language governing rights and 19 * limitations under the License. 20 * 21 * @APPLE_LICENSE_HEADER_END@ 22 */ 23/* 24 * FILE: bootroot.h 25 * AUTH: Soren Spies (sspies) 26 * DATE: 10 March 2011 (Copyright Apple Inc.) 27 * DESC: header for libBootRoot.a 28 */ 29 30#ifndef _BOOTROOT_H_ 31#define _BOOTROOT_H_ 32 33/* 34 * Link to /usr/local/lib/libBootRoot.a via -lBootRoot 35 * 36 * libBootRoot generally requires clients to link against: 37 * ApplicationServices.framework -> -framework ApplicationServices 38 * CoreFoundation.framework -> -framework CoreFoundation 39 * DiskArbitration.framework -> -framework DiskArbitration 40 * IOKit.framework -> -framework IOKit 41 * /usr/local/lib/libbless.a -> add -lbless 42 * only available on 10.7 (see below for 10.6): 43 * /usr/lib/libCoreStorage.dylib -> -lCoreStorage 44 * /usr/lib/libcsfde.dylib -> -lcsfde 45 * EFILogin.framework -> -framework EFILogin 46 * 47 * The use of dead code stripping is strongly recommended to 48 * reduce the number of libraries required. 49 * 50 * The 10.7 libraries can be weak-linked if clients need to run 51 * on 10.6: 52 * Set the "Base SDK" to "Current Mac OS", and set the deployment 53 * target to "Mac OS X 10.6". 10.7-only functions should fail 54 * cleanly if inadvertently called on 10.6 (see caveats at 10831618 55 * and related). 56 * 57 * Several clients 58 * 1. basic "kextcache -u" (Installer, kextd, etc) 59 * 2a. "set up Boot!=Root in an Apple_Boot" (Disk Management for CSFDE) 60 * 2b. "deactivate Boot!=Root in an Apple_Boot" (Disk Management post-CSFDE) 61 * 3a. "custom configure an Apple_Boot to boot off some other volume" (IA) 62 * 3b. "keep system Boot!=Root out of the way" (Install Assistant) 63 * 4a. set up booting within a directory in an Apple_Boot (Time Machine) 64 * 4b. set up booting with a temporary directory (ANI5) 65 * 66 * WARNING: libBootRoot is NOT THREAD-SAFE / re-entrant. It uses 67 * basename(3), dirname(3), relies on internal static storage, and 68 * uses global fchdir() to keep from straying from the target fsys. 69 * Complex multi-threaded programs should probably create a 'brtool' 70 * and call that as a separate process until 10561671 is addressed. 71 */ 72 73#include <CoreFoundation/CoreFoundation.h> 74#include <IOKit/kext/OSKextPrivate.h> 75 76 77#ifdef __cplusplus 78extern "C" { 79#endif 80 81// these bonus functions 82void tool_log( 83 OSKextRef aKext, 84 OSKextLogSpec logSpec, 85 const char * format, 86 ...); 87void tool_openlog(const char * name); 88/* allow clients to configure libBootRoot to send logs to the 89 * system logging facility (ASL) as easily as 90 OSKextSetLogOutputFunction(&tool_log); 91 tool_openlog(getprogname() [/ myCFBundleID]); 92 */ 93 94// and to direct libbless logging to OSKextLog/tool_log 95int32_t BRBLLogFunc(void *refcon, int32_t level, const char *string); 96/* as in: 97 BLContext blctx = { 0, BRBLLogFunc, NULL }; 98 BLFuncStuff(&blctx, ...) 99 */ 100 101 102/*! 103 * @function BRUpdateBootFiles() 104 * @abstract kextcache -u [-f]: update as needed [always] 105 * 106 * @param volRoot - volume to be updated 107 * @param force - copy files regardless of timestamps in volRoot 108 * 109 * @result 0 if caches appear up to date / were copied to the right places. 110 * ?? kPOSIXErrorBase could be used to encode errno ?? 111 * 112 * @discussion 113 * At minimum, ensures that a local-root primory kext cache 114 * (traditional mkext, modern kernelcache) is up to date and 115 * then -- if needed or requested -- copies all Boot!=Root 116 * files to the appropriate helper partition(s) (e.g. Apple_Boot). 117 * 118 * BRUpdateBootFiles() always attempts to lock the volume with 119 * kextd to prevent simultaneous automatic background updates. 120 * 121 * This function should give the same results as spawning 122 * kextcache -u <volRoot> and waiting for it to succeed. 123 * It will, however, perform all timestamp checking in the calling 124 * process. If a kernel/kext cache needs to be rebuilt, it will 125 * launch the current running OS's kextcache. As a result of this 126 * dependency, kernel/kext cache rebuilds are only supported if 127 * the running OS is as new or newer than the target OS. 128 */ 129OSStatus BRUpdateBootFiles(CFURLRef volRoot, Boolean force); 130 131 132/*! 133 * @function BRCopyActiveBootPartitions() 134 * @abstract return list of currently-active Boot!=Root helper partitions 135 * 136 * @param volRoot - volume for which to return helper partitions 137 * 138 * @result CFArrayRef or NULL if no supported helpers 139 * 140 * @discussion 141 * Evaluates the target volume and returns a list of helper 142 * partitions. In the simple case, ths is generally the 143 * Apple_Boot partition following the data-bearing partition 144 * in question. For Apple_HFS/Apple_Boot, this function returns 145 * NULL. This function uses on libbless's 146 * BLCreateBooterInformationDictionary(). 147 */ 148CFArrayRef BRCopyActiveBootPartitions(CFURLRef volRoot); 149 150 151/*! 152 * @function BRCopyBootFiles 153 * @abstract update boot caches and copy files to specified partition 154 * 155 * @param srcVol - root of volume containing source files and bootcaches.plist 156 * @param initialRoot - root of volume to make accessible at boot time 157 * @param helperBSDName - name (like disk0s7) of helper partition 158 * @param bootPrefOverrides - [optional] extra info for com.apple.Boot.plist 159 * 160 * @result 0 if up to date caches were copied, else errno-ish 161 * ?? kPOSIXErrorBase could be used to encode errno ?? 162 * 163 * @discussion 164 * BRCopyBootFiles() copies appropriate boot cache files from a 165 * source volume to a single target partition. BRCopyBootFiles() 166 * updates any out of date caches before copying them to the target. 167 * 168 * The partition referred to by helperBSDName: 169 * - must contain a valid HFS+ filesystem 170 * - should not "belong" to any root volume except initialRoot 171 * - for FDE, must follow initialRoot's Apple_CoreStorage 172 * It will be treated as a helper partition: mounted as 173 * necessary and soft-unmounted regardless of success. 174 * 175 * Once complete, the helper's filesystem will be blessed such 176 * that the option-boot picker will show srcVol's label. If NVRAM 177 * needs to point to the partition before normal invocations of 178 * bless(8) would correctly set it, libbless's BLSetEFIBootDevice() 179 * can be used to point NVRAM at the helper partition. 180 * 181 * Note: srcVol cache updates are made with the running system's 182 * kext subsystem. Behavior is be undefined if a statically- 183 * linked BRCopyBootFiles() is called on an older system when 184 * srcVol's caches are out of date and the older system can't 185 * properly update them. 186 * 187 * If [Boot!=Root has not been disabled and] srcVol and initialRoot 188 * refer to the same volume, its "boot stamps" will be updated to 189 * assure the system's Boot!=Root that everything is "up to date." 190 * 191 * BR*Update*BootFiles() can be used on a volume with the force 192 * argument to get all currently-active helper partition(s) back 193 * in sync with their root volume's content. 194 195[NOT YET: If srcVol and initialRoot are different, BRDisableSystemBootRoot() 196 * should be called on initialRoot so Boot!=Root won't later overwrite 197 * the files copied into the helper partition in question.] 198[XX also need to make it an error if one of two safe modes aren't used: 199 1) srcVol == initialRoot AND helperBSDName == only valid helper 200 -> system Boot!=Root must (should?) be active 201 2) srcVol != initialRoot OR helperBSDName != any default helper 202 -> system Boot!=Root must be disabled] 203 */ 204 205OSStatus BRCopyBootFiles(CFURLRef srcVol, 206 CFURLRef initialRoot, 207 CFStringRef helperBSDName, 208 CFDictionaryRef bootPrefOverrides); 209 210/*! 211 * @function BRCopyBootFilesToDir 212 * @abstract copy up-to-date boot caches to specified partition & directory 213 * 214 * @param srcVol - root of volume containing source files and bootcaches.plist 215 * @param initialRoot - root of volume to make accessible at boot time 216 * @param bootPrefOverrides - [optional] extra info for com.apple.Boot.plist 217 * @param targetBSDName - name (like disk0s7) of target partition 218 * @param targetDir - optional target directory relative to targetBSDName 219 * @param blessSpec - how to bless the files copied; see typedef 220 * @param pickerLabel - [optional] what the option-picker should show 221 * @param options - see BRCopyFilesOpts below 222 * 223 * @result 0 if up to date caches were copied, else errno-ish 224 * ?? kPOSIXErrorBase could be used to encode errno ?? 225 * 226 * @discussion 227 * Similar to BRCopyBootFiles(), BRCopyBootFilesToDir() copies 228 * appropriate boot cache files from a source OS volume to a 229 * directory in a helper partition. Caches are updated if needed, 230 * possibly using the running system's kext infrastructure. 231 * 232 * If targetDir is specified but does not exist, BRCopyBootFilesToDir() 233 * will create it only if (exactly) kBRBlessOnce is specified. 234 * In that case, it will be created within com.apple.boot.once, 235 * a directory which other libBootRoot calls (including 236 * Update(force=true) will clean up. 237 * 238 * If targetDir does exist, BRCopyBootFilesToDir() will allow all 239 * bless options. HOWEVER, BRCopyBootFilesToDir() will still rm -r 240 * and recreate it (mostly an implementation detail that simplifies 241 * error handling). ANY OTHER CONTENT in an existing targetDir WILL 242 * BE DESTROYED. 243 * 244 * To facilitate copying files to a directory that is not on a 245 * helper partition, specifying a target directory will skip 246 * unmounting targetBSDName. If the copy leaves the default 247 * Boot!=Root files "up to date" for srcVol, then the "bootstamps" 248 * of srcVol will be updated (placating BRUpdateBootFiles()). 249 * targetDir cannot be "/". It is recommended to either provide 250 * an existing directory or use a subsystem identifier 251 * (like com.apple.AppleNetInstall.caches). 252 * 253 * While BRCopyBootFiles() can copy boot files to any volume or 254 * directory, CoreStorage-based FDE only unlocks properly if the 255 * the target partition is an Apple_Boot following an 256 * Apple_CoreStorage. 257 * 258 * BRCopyBootFilesToDir() requires a bless specification. This 259 * blessSpec argument controls whether and how the target files 260 * will be "blessed" in the filesystem and/or pointed to directly 261 * or indirectly through efi-boot-* NVRAM variables. 262 */ 263// XX need proper typedef/enum HeaderDoc 264typedef enum { 265 kBRBlessNone = 0, // nothing blessed: just copy the files 266 // (CAUTION: FSDefault is usually better) 267 kBRBlessFSDefault = 1, // fsys: finderinfo[0,1] -> targetDir, boot.efi 268 // (will show up in option-boot picker) 269 // bits 2-7 reserved 270 kBRBlessFull = 0x11, // FSDefault + boot-device->targetPartition 271 // (system will boot these until changed) 272 kBRBlessOnce = 0x20 // efi-boot-next -> dev/boot.efi 273 // (system will boot these files once) 274 // kBRBlessFSDefault|kBRBlessOnce will configure the filesystem(s) 275 // always to boot the target (for example, from the option picker) 276 // but will only set NVRAM to boot it once. 277} BRBlessStyle; 278typedef uint32_t BRCopyFilesOpts; 279#define kBROptsNone 0x0 280#define kBRAnyBootStamps 0x10000 // any bootstamps written to top level 281OSStatus BRCopyBootFilesToDir(CFURLRef srcVol, 282 CFURLRef initialRoot, 283 CFDictionaryRef bootPrefOverrides, 284 CFStringRef targetBSDName, 285 CFURLRef targetDir, 286 BRBlessStyle blessSpec, 287 CFStringRef pickerLabel, 288 BRCopyFilesOpts opts); 289 290/*! 291 * @function BREraseBootFiles 292 * @abstract put a specified helper partition into a pre-Boot!=Root state 293 * 294 * @param srcVolRoot - volume containing source files and bootcaches.plist 295 * @param helperBSDName - name (like disk0s7) of target helper partition 296 * 297 * @result 0 if all Boot!=Root files were removed 298 * (and, ignoring 8952543, any Recovery OS blessed) 299 * ENOTEMPTY if it looks like not everything got cleaned up 300 * 301 * @discussion 302 * BREraseBootFiles() will erase all files previously copied from 303 * srcVolRoot by BRCopyBootFiles(). It will also appropriately 304 * re-activate any Recovery OS present in the helper partition. 305 * The helper is mounted and soft-unmounted in all cases. 306 * 307 * BREraseBootFiles() will allow destruction of an active helper 308 * for srcVol. It is up to the caller to ensure that the volume 309 * is, on disk, backed by a partition understood by the system's 310 * firmware. With live partitioning, a Boot!=Root volume wiil 311 * look like it still requires an Apple_Boot for booting until 312 * after the next reboot. 313 * 314 * XX Installing new boot files to srcVol may cause the system's 315 * Boot!=Root to copy them to the Apple_Boot, negating the 316 * effects of BREraseBootFiles(). kextd detects the partition 317 * type change, but we need to make sure that's enough. 318 */ 319OSStatus BREraseBootFiles(CFURLRef srcVolRoot, CFStringRef helperBSDName); 320 321 322// ---- functions below not yet implemented ---- 323 324/*! 325 * @function BRDisableSystemBootRoot 326 * @abstract stop Boot!=Root from looking at a particular volume 327 * 328 * @param sysVolRoot - volume for which to disable Boot!=Root 329 * 330 * @result 0 if Boot!=Root could no long be watching this volume 331 * 332 * @discussion 333 * This function obtains a lock for the volume from the running 334 * kextd, moves aside the volume's Boot!=Root control file 335 * (/usr/standalone/bootcaches.plist) and then kills kextd 336 * which restarts but no longer watches the volume. 337 */ 338OSStatus BRDisableSystemBootRoot(CFURLRef sysVolRoot); 339 340/*! 341 * @function BRRestoreSystemBootRoot 342 * @abstract re-enable Boot!=Root for a particular volume 343 * 344 * @param sysVolRoot - volume for which to re-enable Boot!=Root 345 * 346 * @result 0 if the system Boot!=Root files are back in place and 347 * Boot!=Root is again watching the volume. 348 * 349 * @discussion 350 * Un-does BRDisableSystemBootRoot(), makes sure kextd is watching 351 * the volume, and forcibly updates all helper partitions, erasing 352 * any trickery which might have been imposed. 353 * [should this final re-update occur via libBootRoot or via the 354 * system's kextcache -u?] 355 */ 356OSStatus BRRestoreSystemBootRoot(CFURLRef sysVolRoot); 357 358 359#ifdef __cplusplus 360} 361#endif 362 363#endif // _BOOTROOT_H_ 364