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