1/*
2 * Copyright (c) 2001-2009 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 *  bless.c
25 *  bless
26 *
27 *  Created by Shantonu Sen <ssen@apple.com> on Wed Nov 14 2001.
28 *  Copyright (c) 2001-2007 Apple Inc. All Rights Reserved.
29 *
30 *  $Id: bless.c,v 1.85 2006/07/17 22:19:05 ssen Exp $
31 *
32 */
33
34#include <stdlib.h>
35#include <stdio.h>
36#include <string.h>
37#include <stdarg.h>
38#include <unistd.h>
39#include <getopt.h>
40#include <err.h>
41#include <sys/stat.h>
42#include <sys/mount.h>
43#include <sys/types.h>
44#include <sys/sysctl.h>
45
46#include "enums.h"
47#include "structs.h"
48
49#include "bless.h"
50#include "bless_private.h"
51#include "protos.h"
52
53struct clarg actargs[klast];
54
55/*
56 * To add an option, allocate an enum in enums.h, add a getopt_long entry here,
57 * add to main(), add to usage and man page
58 */
59
60/* options descriptor */
61static struct option longopts[] = {
62{ "alternateos",    required_argument,      0,              kalternateos},
63{ "alternateOS",    required_argument,      0,              kalternateos},
64{ "bootinfo",       optional_argument,      0,              kbootinfo},
65{ "bootefi",		optional_argument,      0,              kbootefi},
66{ "bootBlockFile",  required_argument,      0,              kbootblockfile },
67{ "bootblockfile",  required_argument,      0,              kbootblockfile },
68{ "booter",         required_argument,      0,              kbooter },
69{ "device",         required_argument,      0,              kdevice },
70{ "firmware",       required_argument,      0,              kfirmware },
71{ "file",           required_argument,      0,              kfile },
72{ "folder",         required_argument,      0,              kfolder },
73{ "folder9",        required_argument,      0,              kfolder9 },
74{ "getBoot",        no_argument,            0,              kgetboot },
75{ "getboot",        no_argument,            0,              kgetboot },
76{ "help",           no_argument,            0,              khelp },
77{ "info",           optional_argument,      0,              kinfo },
78{ "kernel",         required_argument,      0,              kkernel },
79{ "kernelcache",    required_argument,      0,              kkernelcache },
80{ "label",          required_argument,      0,              klabel },
81{ "labelfile",      required_argument,      0,              klabelfile },
82{ "legacy",         no_argument,            0,              klegacy },
83{ "legacydrivehint",required_argument,      0,              klegacydrivehint },
84{ "mkext",          required_argument,      0,              kmkext },
85{ "mount",          required_argument,      0,              kmount },
86{ "netboot",        no_argument,            0,              knetboot},
87{ "nextonly",       no_argument,            0,              knextonly},
88{ "openfolder",     required_argument,      0,              kopenfolder },
89{ "options",        required_argument,      0,              koptions },
90{ "payload",        required_argument,      0,              kpayload },
91{ "plist",          no_argument,            0,              kplist },
92{ "quiet",          no_argument,            0,              kquiet },
93{ "recovery",		no_argument,            0,              krecovery },
94{ "reset",          no_argument,            0,              kreset },
95{ "save9",          no_argument,            0,              ksave9 },
96{ "saveX",          no_argument,            0,              ksaveX },
97{ "server",         required_argument,      0,              kserver },
98{ "setBoot",        no_argument,            0,              ksetboot },
99{ "setboot",        no_argument,            0,              ksetboot },
100{ "setOF",          no_argument,            0,              ksetboot }, // legacy option name
101{ "shortform",      no_argument,            0,              kshortform },
102{ "startupfile",    required_argument,      0,              kstartupfile },
103{ "unbless",        required_argument,      0,              kunbless },
104{ "use9",           no_argument,            0,              kuse9 },
105{ "verbose",        no_argument,            0,              kverbose },
106{ "version",        no_argument,            0,              kversion },
107{ 0,            0,                      0,              0 }
108};
109
110extern char *optarg;
111extern int optind;
112
113int main (int argc, char * argv[])
114{
115
116    int ch, longindex;
117    BLContext context;
118    struct blesscon bcon;
119    extern double blessVersionNumber;
120
121    bcon.quiet = 0;
122    bcon.verbose = 0;
123
124    context.version = 0;
125    context.logstring = blesslog;
126    context.logrefcon = &bcon;
127
128    if(argc == 1) {
129        usage_short();
130    }
131
132    if(getenv("BL_PRINT_ARGUMENTS")) {
133        int i;
134        for(i=0; i < argc; i++) {
135            fprintf(stderr, "argv[%d] = '%s'\n", i, argv[i]);
136        }
137    }
138
139
140
141    while ((ch = getopt_long_only(argc, argv, "", longopts, &longindex)) != -1) {
142
143        switch(ch) {
144            case khelp:
145                usage();
146                break;
147            case kquiet:
148                break;
149            case kverbose:
150                bcon.verbose = 1;
151                break;
152            case kversion:
153                printf("%.1f\n", blessVersionNumber);
154                exit(0);
155                break;
156            case kpayload:
157                actargs[ch].present = 1;
158                break;
159            case ksave9:
160                // ignore, this is now always saved as alternateos
161                break;
162			case kbootblockfile:
163				errx(1, "The bootblockfile option is now obsolete.");
164				break;
165            case '?':
166            case ':':
167                usage_short();
168                break;
169            default:
170                // common handling for all other options
171            {
172                struct option *opt = &longopts[longindex];
173
174
175                if(actargs[ch].present) {
176                    warnx("Option \"%s\" already specified", opt->name);
177                    usage_short();
178                    break;
179                } else {
180                    actargs[ch].present = 1;
181                }
182
183                switch(opt->has_arg) {
184                    case no_argument:
185                        actargs[ch].hasArg = 0;
186                        break;
187                    case required_argument:
188                        actargs[ch].hasArg = 1;
189                        strlcpy(actargs[ch].argument, optarg, sizeof(actargs[ch].argument));
190                        break;
191                    case optional_argument:
192                        if(argv[optind] && argv[optind][0] != '-') {
193                            actargs[ch].hasArg = 1;
194                            strlcpy(actargs[ch].argument, argv[optind], sizeof(actargs[ch].argument));
195                        } else {
196                            actargs[ch].hasArg = 0;
197                        }
198                        break;
199                }
200            }
201                break;
202        }
203    }
204
205    argc -= optind;
206    argc += optind;
207
208    /* There are 5 public modes of execution: info, device, folder, netboot, unbless
209     * There is 1 private mode: firmware
210     * These are all one-way function jumps.
211     */
212
213    /* If it was requested, print out the Finder Info words */
214    if(actargs[kinfo].present || actargs[kgetboot].present) {
215        return modeInfo(&context, actargs);
216    }
217
218    if(actargs[kdevice].present) {
219        return modeDevice(&context, actargs);
220    }
221
222	if(actargs[kfirmware].present) {
223		return modeFirmware(&context, actargs);
224	}
225
226	if(actargs[knetboot].present) {
227		return modeNetboot(&context, actargs);
228	}
229
230	if (actargs[kunbless].present) {
231		return modeUnbless(&context, actargs);
232	}
233
234    /* default */
235    return modeFolder(&context, actargs);
236
237}
238
239
240
241// note that libbless has its own (similar) contextprintf()
242int blesscontextprintf(BLContextPtr context, int loglevel, char const *fmt, ...) {
243    int ret;
244    char *out;
245    va_list ap;
246
247    va_start(ap, fmt);
248    ret = vasprintf(&out, fmt, ap);
249    va_end(ap);
250
251    if((ret == -1) || (out == NULL)) {
252        return context->logstring(context->logrefcon, loglevel, "Memory error, log entry not available");
253    }
254
255    ret = context->logstring(context->logrefcon, loglevel, out);
256    free(out);
257    return ret;
258}
259
260