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 * However, it will perform everything except kernel cache 124 * building in the calling process. When running on an older 125 * OS, volRoot's source caches must already be up to date. 126 */ 127OSStatus BRUpdateBootFiles(CFURLRef volRoot, Boolean force); 128 129 130/*! 131 * @function BRCopyActiveBootPartitions() 132 * @abstract return list of currently-active Boot!=Root helper partitions 133 * 134 * @param volRoot - volume for which to return helper partitions 135 * 136 * @result CFArrayRef or NULL if no supported helpers 137 * 138 * @discussion 139 * Evaluates the target volume and returns a list of helper 140 * partitions. In the simple case, ths is generally the 141 * Apple_Boot partition following the data-bearing partition 142 * in question. For Apple_HFS/Apple_Boot, this function returns 143 * NULL. This function uses on libbless's 144 * BLCreateBooterInformationDictionary(). 145 */ 146CFArrayRef BRCopyActiveBootPartitions(CFURLRef volRoot); 147 148 149/*! 150 * @function BRCopyBootFiles 151 * @abstract update boot caches and copy files to specified partition 152 * 153 * @param srcVol - root of volume containing source files and bootcaches.plist 154 * @param initialRoot - root of volume to make accessible at boot time 155 * @param helperBSDName - name (like disk0s7) of helper partition 156 * @param bootPrefOverrides - [optional] extra info for com.apple.Boot.plist 157 * 158 * @result 0 if up to date caches were copied, else errno-ish 159 * ?? kPOSIXErrorBase could be used to encode errno ?? 160 * 161 * @discussion 162 * BRCopyBootFiles() copies appropriate boot cache files from a 163 * source volume to a single target partition. BRCopyBootFiles() 164 * updates any out of date caches before copying them to the target. 165 * 166 * The partition referred to by helperBSDName: 167 * - must contain a valid HFS+ filesystem 168 * - should not "belong" to any root volume except initialRoot 169 * - for FDE, must follow initialRoot's Apple_CoreStorage 170 * It will be treated as a helper partition: mounted as 171 * necessary and soft-unmounted regardless of success. 172 * 173 * Once complete, the helper's filesystem will be blessed such 174 * that the option-boot picker will show srcVol's label. If NVRAM 175 * needs to point to the partition before normal invocations of 176 * bless(8) would correctly set it, libbless's BLSetEFIBootDevice() 177 * can be used to point NVRAM at the helper partition. 178 * 179 * Note: srcVol cache updates are made with the running system's 180 * kext subsystem. Behavior is be undefined if a statically- 181 * linked BRCopyBootFiles() is called on an older system when 182 * srcVol's caches are out of date and the older system can't 183 * properly update them. 184 * 185 * If [Boot!=Root has not been disabled and] srcVol and initialRoot 186 * refer to the same volume, its "boot stamps" will be updated to 187 * assure the system's Boot!=Root that everything is "up to date." 188 * 189 * BR*Update*BootFiles() can be used on a volume with the force 190 * argument to get all currently-active helper partition(s) back 191 * in sync with their root volume's content. 192 193[NOT YET: If srcVol and initialRoot are different, BRDisableSystemBootRoot() 194 * should be called on initialRoot so Boot!=Root won't later overwrite 195 * the files copied into the helper partition in question.] 196[XX also need to make it an error if one of two safe modes aren't used: 197 1) srcVol == initialRoot AND helperBSDName == only valid helper 198 -> system Boot!=Root must (should?) be active 199 2) srcVol != initialRoot OR helperBSDName != any default helper 200 -> system Boot!=Root must be disabled] 201 */ 202 203OSStatus BRCopyBootFiles(CFURLRef srcVol, 204 CFURLRef initialRoot, 205 CFStringRef helperBSDName, 206 CFDictionaryRef bootPrefOverrides); 207 208/*! 209 * @function BRCopyBootFilesToDir 210 * @abstract copy up-to-date boot caches to specified partition & directory 211 * 212 * @param srcVol - root of volume containing source files and bootcaches.plist 213 * @param initialRoot - root of volume to make accessible at boot time 214 * @param bootPrefOverrides - [optional] extra info for com.apple.Boot.plist 215 * @param targetBSDName - name (like disk0s7) of target partition 216 * @param targetDir - optional target directory relative to targetBSDName 217 * @param blessSpec - how to bless the files copied; see typedef 218 * @param pickerLabel - [optional] what the option-picker should show 219 * @param options - see BRCopyFilesOpts below 220 * 221 * @result 0 if up to date caches were copied, else errno-ish 222 * ?? kPOSIXErrorBase could be used to encode errno ?? 223 * 224 * @discussion 225 * Similar to BRCopyBootFiles(), BRCopyBootFilesToDir() copies 226 * appropriate boot cache files from a source OS volume to a 227 * directory in a helper partition. Caches are updated if needed, 228 * possibly using the running system's kext infrastructure. 229 * 230 * If targetDir is specified but does not exist, BRCopyBootFilesToDir() 231 * will create it only if (exactly) kBRBlessOnce is specified. 232 * In that case, it will be created within com.apple.boot.once, 233 * a directory which other libBootRoot calls (including 234 * Update(force=true) will clean up. 235 * 236 * If targetDir does exist, BRCopyBootFilesToDir() will allow all 237 * bless options. HOWEVER, BRCopyBootFilesToDir() will still rm -r 238 * and recreate it (mostly an implementation detail that simplifies 239 * error handling). ANY OTHER CONTENT in an existing targetDir WILL 240 * BE DESTROYED. 241 * 242 * To facilitate copying files to a directory that is not on a 243 * helper partition, specifying a target directory will skip 244 * unmounting targetBSDName. If the copy leaves the default 245 * Boot!=Root files "up to date" for srcVol, then the "bootstamps" 246 * of srcVol will be updated (placating BRUpdateBootFiles()). 247 * targetDir cannot be "/". It is recommended to either provide 248 * an existing directory or use a subsystem identifier 249 * (like com.apple.AppleNetInstall.caches). 250 * 251 * While BRCopyBootFiles() can copy boot files to any volume or 252 * directory, CoreStorage-based FDE only unlocks properly if the 253 * the target partition is an Apple_Boot following an 254 * Apple_CoreStorage. 255 * 256 * BRCopyBootFilesToDir() requires a bless specification. This 257 * blessSpec argument controls whether and how the target files 258 * will be "blessed" in the filesystem and/or pointed to directly 259 * or indirectly through efi-boot-* NVRAM variables. 260 */ 261// XX need proper typedef/enum HeaderDoc 262typedef enum { 263 kBRBlessNone = 0, // nothing blessed: just copy the files 264 // (CAUTION: FSDefault is usually better) 265 kBRBlessFSDefault = 1, // fsys: finderinfo[0,1] -> targetDir, boot.efi 266 // (will show up in option-boot picker) 267 // bits 2-7 reserved 268 kBRBlessFull = 0x11, // FSDefault + boot-device->targetPartition 269 // (system will boot these until changed) 270 kBRBlessOnce = 0x20 // efi-boot-next -> dev/boot.efi 271 // (system will boot these files once) 272 // kBRBlessFSDefault|kBRBlessOnce will configure the filesystem(s) 273 // always to boot the target (for example, from the option picker) 274 // but will only set NVRAM to boot it once. 275} BRBlessStyle; 276typedef uint32_t BRCopyFilesOpts; 277#define kBROptsNone 0x0 278#define kBRAnyBootStamps 0x10000 // any bootstamps written to top level 279OSStatus BRCopyBootFilesToDir(CFURLRef srcVol, 280 CFURLRef initialRoot, 281 CFDictionaryRef bootPrefOverrides, 282 CFStringRef targetBSDName, 283 CFURLRef targetDir, 284 BRBlessStyle blessSpec, 285 CFStringRef pickerLabel, 286 BRCopyFilesOpts opts); 287 288/*! 289 * @function BREraseBootFiles 290 * @abstract put a specified helper partition into a pre-Boot!=Root state 291 * 292 * @param srcVolRoot - volume containing source files and bootcaches.plist 293 * @param helperBSDName - name (like disk0s7) of target helper partition 294 * 295 * @result 0 if all Boot!=Root files were removed 296 * (and, ignoring 8952543, any Recovery OS blessed) 297 * ENOTEMPTY if it looks like not everything got cleaned up 298 * 299 * @discussion 300 * BREraseBootFiles() will erase all files previously copied from 301 * srcVolRoot by BRCopyBootFiles(). It will also appropriately 302 * re-activate any Recovery OS present in the helper partition. 303 * The helper is mounted and soft-unmounted in all cases. 304 * 305 * BREraseBootFiles() will allow destruction of an active helper 306 * for srcVol. It is up to the caller to ensure that the volume 307 * is, on disk, backed by a partition understood by the system's 308 * firmware. With live partitioning, a Boot!=Root volume wiil 309 * look like it still requires an Apple_Boot for booting until 310 * after the next reboot. 311 * 312 * XX Installing new boot files to srcVol may cause the system's 313 * Boot!=Root to copy them to the Apple_Boot, negating the 314 * effects of BREraseBootFiles(). kextd detects the partition 315 * type change, but we need to make sure that's enough. 316 */ 317OSStatus BREraseBootFiles(CFURLRef srcVolRoot, CFStringRef helperBSDName); 318 319 320// ---- functions below not yet implemented ---- 321 322/*! 323 * @function BRDisableSystemBootRoot 324 * @abstract stop Boot!=Root from looking at a particular volume 325 * 326 * @param sysVolRoot - volume for which to disable Boot!=Root 327 * 328 * @result 0 if Boot!=Root could no long be watching this volume 329 * 330 * @discussion 331 * This function obtains a lock for the volume from the running 332 * kextd, moves aside the volume's Boot!=Root control file 333 * (/usr/standalone/bootcaches.plist) and then kills kextd 334 * which restarts but no longer watches the volume. 335 */ 336OSStatus BRDisableSystemBootRoot(CFURLRef sysVolRoot); 337 338/*! 339 * @function BRRestoreSystemBootRoot 340 * @abstract re-enable Boot!=Root for a particular volume 341 * 342 * @param sysVolRoot - volume for which to re-enable Boot!=Root 343 * 344 * @result 0 if the system Boot!=Root files are back in place and 345 * Boot!=Root is again watching the volume. 346 * 347 * @discussion 348 * Un-does BRDisableSystemBootRoot(), makes sure kextd is watching 349 * the volume, and forcibly updates all helper partitions, erasing 350 * any trickery which might have been imposed. 351 * [should this final re-update occur via libBootRoot or via the 352 * system's kextcache -u?] 353 */ 354OSStatus BRRestoreSystemBootRoot(CFURLRef sysVolRoot); 355 356 357#ifdef __cplusplus 358} 359#endif 360 361#endif // _BOOTROOT_H_ 362