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