1/*
2 *  kextcache_main.h
3 *  kext_tools
4 *
5 *  Created by nik on 5/20/08.
6 *  Copyright 2008 __MyCompanyName__. All rights reserved.
7 *
8 */
9#ifndef _KEXTCACHE_MAIN_H
10#define _KEXTCACHE_MAIN_H
11
12#include <CoreFoundation/CoreFoundation.h>
13#include <IOKit/kext/OSKext.h>
14
15#include <getopt.h>
16#include <sysexits.h>
17
18#include <IOKit/kext/OSKext.h>
19
20#include "kext_tools_util.h"
21#include "kernelcache.h"
22#include "bootroot_internal.h"
23
24#pragma mark Basic Types & Constants
25/*******************************************************************************
26* Constants
27*******************************************************************************/
28
29enum {
30    kKextcacheExitOK          = EX_OK,
31    kKextcacheExitNotFound,
32    kKextcacheExitArchNotFound,
33    kKextcacheExitKextBad,
34    kKextcacheExitStale,
35
36    // don't think we use it
37    kKextcacheExitUnspecified = 11,
38
39    // don't actually exit with this, it's just a sentinel value
40    kKextcacheExitHelp        = 33,
41    kKextcacheExitNoStart
42};
43
44#pragma mark Command-line Option Definitions
45/*******************************************************************************
46* Command-line options. This data is used by getopt_long_only().
47*
48* Options common to all kext tools are in kext_tools_util.h.
49*******************************************************************************/
50
51/* Mkext-generation flags.
52 */
53// kOptNameMkext always represents most recent format supported
54#define kOptNameMkext                   "mkext"
55#define kOptNameMkext1                  "mkext1"
56#define kOptNameMkext2                  "mkext2"
57#define kOptNameSystemMkext             "system-mkext"
58#define kOptNameVolumeRoot              "volume-root"
59
60// kOptNameBundleIdentifier in kext_tools_util.h
61// kOptNameSystemExtensions in kext_tools_util.h
62
63#define kOptNameLocalRoot               "local-root"
64#define kOptNameLocalRootAll            "local-root-all"
65#define kOptNameNetworkRoot             "network-root"
66#define kOptNameNetworkRootAll          "network-root-all"
67#define kOptNameSafeBoot                "safe-boot"
68#define kOptNameSafeBootAll             "safe-boot-all"
69
70/* Prelinked-kernel-generation flags.
71 */
72#define kOptNamePrelinkedKernel         "prelinked-kernel"
73#define kOptNameSystemPrelinkedKernel   "system-prelinked-kernel"
74#define kOptNameKernel                  "kernel"
75#define kOptNameAllLoaded               "all-loaded"
76#define kOptNameSymbols                 "symbols"
77
78/* Embedded prelinked-kernel-generation flags.
79 */
80#define kOptNameAllPersonalities        "all-personalities"
81#define kOptNameNoLinkFailures          "no-link-failures"
82#define kOptNameStripSymbols            "strip-symbols"
83
84/* Misc. cache update flags.
85 */
86#define kOptNameSystemCaches            "system-caches"
87
88/* Boot!=root flags.
89 */
90#define kOptNameInvalidate              "invalidate"
91#define kOptNameUpdate                  "update-volume"
92#define kOptNameForce                   "force"
93#define kOptNameInstaller               "Installer"
94#define kOptNameCachesOnly              "caches-only"
95#define kOptNameEarlyBoot               "Boot"
96
97/* Misc flags.
98 */
99#define kOptNameNoAuthentication        "no-authentication"
100#define kOptNameTests                   "print-diagnostics"
101#define kOptNameCompressed              "compressed"
102#define kOptNameUncompressed            "uncompressed"
103
104#define kOptArch                  'a'
105// 'b' in kext_tools_util.h
106#define kOptPrelinkedKernel       'c'
107#define kOptSystemMkext           'e'
108#if !NO_BOOT_ROOT
109#define kOptForce                 'f'
110#endif /* !NO_BOOT_ROOT */
111
112// xxx - do we want a longopt for this?
113#define kOptLowPriorityFork       'F'
114// 'h' in kext_tools_util.h
115#define kOptInvalidate            'i'
116#define kOptRepositoryCaches      'k'
117#define kOptKernel                'K'
118#define kOptLocalRoot             'l'
119#define kOptLocalRootAll          'L'
120// kOptMkext always represents most recent format supported
121#define kOptMkext                 'm'
122#define kOptNetworkRoot           'n'
123#define kOptNetworkRootAll        'N'
124// 'q' in kext_tools_util.h
125#define kOptAllLoaded             'r'
126#define kOptSafeBoot              's'
127#define kOptSafeBootAll           'S'
128#define kOptTests                 't'
129#if !NO_BOOT_ROOT
130#define kOptUpdate                'u'
131#define kOptCheckUpdate           'U'
132#endif /* !NO_BOOT_ROOT */
133// 'v' in kext_tools_util.h
134#define kOptNoAuthentication      'z'
135
136/* Options with no single-letter variant.  */
137// Do not use -1, that's getopt() end-of-args return value
138// and can cause confusion
139#define kLongOptLongindexHack             (-2)
140#define kLongOptMkext1                    (-3)
141#define kLongOptMkext2                    (-4)
142// kLongOptMkext always represents most recent format supported
143#define kLongOptMkext                     kLongOptMkext2
144#define kLongOptCompressed                (-5)
145#define kLongOptUncompressed              (-6)
146#define kLongOptSymbols                   (-7)
147#define kLongOptSystemCaches              (-8)
148#define kLongOptSystemPrelinkedKernel     (-9)
149#define kLongOptVolumeRoot               (-10)
150#define kLongOptAllPersonalities         (-11)
151#define kLongOptNoLinkFailures           (-12)
152#define kLongOptStripSymbols             (-13)
153#define kLongOptInstaller                (-14)
154#define kLongOptCachesOnly               (-15)
155#define kLongOptEarlyBoot                (-16)
156
157#if !NO_BOOT_ROOT
158#define kOptChars                ":a:b:c:efFhi:kK:lLm:nNqrsStu:U:vz"
159#else
160#define kOptChars                ":a:b:c:eFhkK:lLm:nNqrsStvz"
161#endif /* !NO_BOOT_ROOT */
162/* Some options are now obsolete:
163 *     -F (fork)
164 *     -k (update plist cache)
165 */
166
167int longopt = 0;
168
169struct option sOptInfo[] = {
170    { kOptNameLongindexHack,         no_argument,        &longopt, kLongOptLongindexHack },
171
172    { kOptNameHelp,                  no_argument,        NULL,     kOptHelp },
173    { kOptNameQuiet,                 no_argument,        NULL,     kOptQuiet },
174    { kOptNameVerbose,               optional_argument,  NULL,     kOptVerbose },
175    { kOptNameCompressed,            no_argument,        &longopt, kLongOptCompressed },
176    { kOptNameUncompressed,          no_argument,        &longopt, kLongOptUncompressed },
177
178    { kOptNameArch,                  required_argument,  NULL,     kOptArch },
179
180    { kOptNameMkext1,                required_argument,  &longopt, kLongOptMkext1 },
181    { kOptNameMkext2,                required_argument,  &longopt, kLongOptMkext2 },
182    { kOptNameMkext,                 required_argument,  NULL,     kOptMkext },
183    { kOptNameSystemMkext,           no_argument,        NULL,     kOptSystemMkext },
184    { kOptNameVolumeRoot,            required_argument,  &longopt, kLongOptVolumeRoot },
185
186    { kOptNameSystemCaches,          no_argument,        &longopt, kLongOptSystemCaches },
187
188    { kOptNameBundleIdentifier,      required_argument,  NULL,     kOptBundleIdentifier },
189
190    { kOptNameLocalRoot,             no_argument,        NULL,     kOptLocalRoot },
191    { kOptNameLocalRootAll,          no_argument,        NULL,     kOptLocalRootAll },
192    { kOptNameNetworkRoot,           no_argument,        NULL,     kOptNetworkRoot },
193    { kOptNameNetworkRootAll,        no_argument,        NULL,     kOptNetworkRootAll, },
194    { kOptNameSafeBoot,              no_argument,        NULL,     kOptSafeBoot },
195    { kOptNameSafeBootAll,           no_argument,        NULL,     kOptSafeBootAll },
196
197    { kOptNamePrelinkedKernel,       optional_argument,  NULL,     kOptPrelinkedKernel },
198    { kOptNameSystemPrelinkedKernel, no_argument,        &longopt, kLongOptSystemPrelinkedKernel },
199    { kOptNameKernel,                required_argument,  NULL,     kOptKernel },
200    { kOptNameAllLoaded,             no_argument,        NULL,     kOptAllLoaded },
201    { kOptNameSymbols,               required_argument,  &longopt, kLongOptSymbols },
202
203    { kOptNameAllPersonalities,      no_argument,        &longopt, kLongOptAllPersonalities },
204    { kOptNameNoLinkFailures,        no_argument,        &longopt, kLongOptNoLinkFailures },
205    { kOptNameStripSymbols,          no_argument,        &longopt, kLongOptStripSymbols },
206
207#if !NO_BOOT_ROOT
208    { kOptNameInvalidate,            required_argument,  NULL,     kOptInvalidate },
209    { kOptNameUpdate,                required_argument,  NULL,     kOptUpdate },
210    { kOptNameForce,                 no_argument,        NULL,     kOptForce },
211    { kOptNameInstaller,             no_argument,        &longopt, kLongOptInstaller },
212    { kOptNameCachesOnly,            no_argument,        &longopt, kLongOptCachesOnly },
213    { kOptNameEarlyBoot,             no_argument,        &longopt, kLongOptEarlyBoot },
214#endif /* !NO_BOOT_ROOT */
215
216    { kOptNameNoAuthentication,      no_argument,        NULL,     kOptNoAuthentication },
217    { kOptNameTests,                 no_argument,        NULL,     kOptTests },
218
219#if !NO_BOOT_ROOT
220    { NULL,                          required_argument,  NULL,     kOptCheckUpdate },
221#endif /* !NO_BOOT_ROOT */
222    { NULL,                          no_argument,        NULL,     kOptLowPriorityFork },
223
224    { NULL, 0, NULL, 0 }  // sentinel to terminate list
225};
226
227typedef struct {
228    OSKextRequiredFlags requiredFlagsRepositoriesOnly;  // -l/-n/-s
229    OSKextRequiredFlags requiredFlagsAll;              // -L/-N/-S
230
231    Boolean   updateSystemCaches;   // -system-caches
232    Boolean   lowPriorityFlag;      // -F
233    Boolean   printTestResults;     // -t
234    Boolean   skipAuthentication;   // -z
235
236    CFURLRef  volumeRootURL;        // for mkext/prelinked kernel
237
238    char    * mkextPath;         // mkext option arg
239    int       mkextVersion;      // -mkext1/-mkext2  0 (no mkext, 1 (old format),
240                                    // or 2 (new format)
241
242    char    * prelinkedKernelPath;            // -c option
243    Boolean   needDefaultPrelinkedKernelInfo; // -c option w/o arg;
244                                              // prelinkedKernelURL is parent
245                                              // directory of final kernelcache
246                                              // until we create the cache
247
248    Boolean   needLoadedKextInfo;           // -r option
249    Boolean   generatePrelinkedSymbols;     // -symbols option
250    Boolean   includeAllPersonalities;      // -all-personalities option
251    Boolean   noLinkFailures;               // -no-link-failures option
252    Boolean   stripSymbols;                 // -strip-symbols option
253    CFURLRef  compressedPrelinkedKernelURL; // -uncompress option
254
255    CFURLRef  updateVolumeURL;      // -u / -U OR -i / -invalidate options
256
257    // see BRUpdateOpts_t in bootroot_internal.h
258    BRUpdateOpts_t updateOpts;      // -U, -f, -Installer, ...
259
260    char    * kernelPath;    // overriden by -kernel option
261    CFDataRef kernelFile;    // contents of kernelURL
262    CFURLRef  symbolDirURL;  // -s option;
263
264    CFMutableSetRef    kextIDs;          // -b; must release
265    CFMutableArrayRef  argURLs;          // directories & kexts in order
266    CFMutableArrayRef  repositoryURLs;  // array of CFURLRefs for extensions dirs
267    CFMutableArrayRef  namedKextURLs;
268    CFMutableArrayRef  targetArchs;
269    Boolean            explicitArch;  // user-provided instead of inferred host arches
270
271    CFArrayRef         allKexts;         // directories + named
272    CFArrayRef         repositoryKexts;  // all from directories (may include named)
273    CFArrayRef         namedKexts;
274    CFArrayRef         loadedKexts;
275
276    struct timeval     kernelTimes[2];          // access and mod times of kernel file
277    struct timeval     extensionsDirTimes[2];   // access and mod times of extensions directory with most recent change
278    Boolean     compress;
279    Boolean     uncompress;
280} KextcacheArgs;
281
282#pragma mark Function Prototypes
283/*******************************************************************************
284* Function Prototypes
285*******************************************************************************/
286ExitStatus readArgs(
287    int            * argc,
288    char * const  ** argv,
289    KextcacheArgs  * toolArgs);
290void setDefaultArchesIfNeeded(KextcacheArgs * toolArgs);
291void addArch(
292    KextcacheArgs * toolArgs,
293    const NXArchInfo  * arch);
294const NXArchInfo * addArchForName(
295    KextcacheArgs * toolArgs,
296    const char    * archname);
297ExitStatus readPrelinkedKernelArgs(
298    KextcacheArgs * toolArgs,
299    int             argc,
300    char * const  * argv,
301    Boolean         isLongopt);
302ExitStatus setPrelinkedKernelArgs(
303    KextcacheArgs * toolArgs,
304    char          * filename);
305Boolean setDefaultKernel(KextcacheArgs * toolArgs);
306Boolean setDefaultPrelinkedKernel(KextcacheArgs * toolArgs);
307void setSystemExtensionsFolders(KextcacheArgs * toolArgs);
308ExitStatus doUpdateVolume(KextcacheArgs *toolArgs);
309
310void checkKextdSpawnedFilter(Boolean kernelFlag);
311ExitStatus checkArgs(KextcacheArgs * toolArgs);
312
313ExitStatus getLoadedKextInfo(KextcacheArgs *toolArgs);
314ExitStatus updateSystemPlistCaches(KextcacheArgs * toolArgs);
315ExitStatus updateDirectoryCaches(
316    KextcacheArgs * toolArgs,
317    CFURLRef folderURL);
318ExitStatus createMkext(
319    KextcacheArgs * toolArgs,
320    Boolean       * fatalOut);
321ExitStatus filterKextsForCache(
322    KextcacheArgs     * toolArgs,
323    CFMutableArrayRef   kextArray,
324    const NXArchInfo  * arch,
325    Boolean           * fatalOut);
326Boolean checkKextForArchive(
327    KextcacheArgs       toolArgs,
328    OSKextRef           aKext,
329    const char        * archiveTypeName,
330    const NXArchInfo  * archInfo,
331    OSKextRequiredFlags requiredFlags);
332Boolean kextMatchesFilter(
333    KextcacheArgs             * toolArgs,
334    OSKextRef                   theKext,
335    OSKextRequiredFlags         requiredFlags);
336ExitStatus getFileURLModTimePlusOne(
337    CFURLRef            fileURL,
338    struct timeval    * origModTime,
339    struct timeval      cacheFileTimes[2]);
340ExitStatus getFilePathModTimePlusOne(
341    const char        * filePath,
342    struct timeval    * origModTime,
343    struct timeval      cacheFileTimes[2]);
344Boolean kextMatchesLoadedKextInfo(
345    KextcacheArgs     * toolArgs,
346    OSKextRef           theKext);
347ExitStatus createPrelinkedKernelArchs(
348    KextcacheArgs     * toolArgs,
349    CFMutableArrayRef * prelinkArchsOut);
350ExitStatus createExistingPrelinkedSlices(
351    KextcacheArgs     * toolArgs,
352    CFMutableArrayRef * prelinkedSlicesOut,
353    CFMutableArrayRef * prelinkedArchsOut);
354ExitStatus createPrelinkedKernel(
355    KextcacheArgs     * toolArgs);
356CFArrayRef mergeArchs(
357    CFArrayRef  archSet1,
358    CFArrayRef  archSet2);
359ExitStatus createPrelinkedKernelForArch(
360    KextcacheArgs       * toolArgs,
361    CFDataRef           * prelinkedKernelOut,
362    CFDictionaryRef     * prelinkedSymbolsOut,
363    const NXArchInfo    * archInfo);
364ExitStatus getExpectedPrelinkedKernelModTime(
365    KextcacheArgs  * toolArgs,
366    struct timeval   cacheFileTimes[2],
367    Boolean        * updateModTimeOut);
368ExitStatus compressPrelinkedKernel(
369    CFURLRef            volumeRootURL,
370    const char        * prelinkedKernelPath,
371    Boolean             compress);
372
373void usage(UsageLevel usageLevel);
374
375#endif /* _KEXTCACHE_MAIN_H */
376