#include <CoreFoundation/CoreFoundation.h>
#include <CoreServices/CoreServices.h>
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include "enums.h"
#include "structs.h"
#include "bless.h"
#include "bootconfig.h"
extern int blesscontextprintf(BLContextPtr context, int loglevel, char const *fmt, ...);
static int isOFLabel(const char *data, int labelsize);
int modeFolder(BLContextPtr context, struct clopt commandlineopts[klast], struct clarg actargs[klast]) {
int err;
int isHFS;
uint32_t folderXid = 0; uint32_t folder9id = 0;
if(!(geteuid() == 0)) {
blesscontextprintf(context, kBLLogLevelError, "Not run as root\n" );
return 1;
}
if(actargs[kmount].present) {
err = BLGetCommonMountPoint(context, actargs[kmount].argument, "", actargs[kmount].argument);
if(err) {
blesscontextprintf(context, kBLLogLevelError, "Can't determine mount point of '%s'\n", actargs[kmount].argument );
} else {
blesscontextprintf(context, kBLLogLevelVerbose, "Mount point is '%s'\n", actargs[kmount].argument );
}
actargs[ksave9].present = 1;
actargs[ksaveX].present = 1;
} else {
err = BLGetCommonMountPoint(context, actargs[kfolder].argument, actargs[kfolder9].argument, actargs[kmount].argument);
if(err) {
blesscontextprintf(context, kBLLogLevelError, "Can't determine mount point of '%s' and '%s'\n",
actargs[kfolder].argument, actargs[kfolder9].argument);
return 1;
} else {
blesscontextprintf(context, kBLLogLevelVerbose, "Common mount point of '%s' and '%s' is %s\n",
actargs[kfolder].argument,
actargs[kfolder9].argument, actargs[kmount].argument );
}
}
if(actargs[kbootinfo].present) {
if(actargs[kfolder].present) {
CFDataRef bootXdata = NULL;
err = BLLoadFile(context, actargs[kbootinfo].argument, 0, &bootXdata);
if(err) {
blesscontextprintf(context, kBLLogLevelError, "Could not load BootX data from %s\n",
actargs[kbootinfo].argument);
} else {
err = BLCreateFile(context, bootXdata, actargs[kfolder].argument, "BootX", 0, kBL_OSTYPE_PPC_TYPE_BOOTX, kBL_OSTYPE_PPC_CREATOR_CHRP);
if(err) {
blesscontextprintf(context, kBLLogLevelError, "Could not create BootX in %s\n", actargs[kfolder].argument );
} else {
blesscontextprintf(context, kBLLogLevelVerbose, "BootX created successfully in %s\n",
actargs[kfolder].argument );
}
}
} else {
blesscontextprintf(context, kBLLogLevelVerbose, "Could not create BootX, no X folder specified\n" );
}
} else {
blesscontextprintf(context, kBLLogLevelVerbose, "No BootX creation requested\n" );
}
if(actargs[ksystemfile].present) {
if(actargs[kfolder9].present || actargs[kfolder].present) {
CFDataRef systemdata = NULL;
err = BLLoadFile(context, actargs[ksystemfile].argument, 0, &systemdata);
if(err) {
blesscontextprintf(context, kBLLogLevelError, "Could not load system file data from %s\n",
actargs[ksystemfile].argument);
} else {
err = BLCreateFile(context, (void *)systemdata,
actargs[kfolder9].present ? actargs[kfolder9].argument : actargs[kfolder].argument,
"System", 1, 'zsys', 'MACS');
if(err) {
blesscontextprintf(context, kBLLogLevelError, "Could not create System in %s\n",
actargs[kfolder9].argument );
} else {
blesscontextprintf(context, kBLLogLevelVerbose, "System created successfully in %s\n",
actargs[kfolder9].argument );
}
}
} else {
blesscontextprintf(context, kBLLogLevelVerbose, "Could not create System file, no folder specified\n" );
}
}
err = BLIsMountHFS(context, actargs[kmount].argument, &isHFS);
if(err) {
blesscontextprintf(context, kBLLogLevelError, "Could not determine filesystem of %s\n", actargs[kmount].argument );
return 1;
}
if(isHFS && (actargs[kfolder].present || actargs[kfolder9].present)) {
uint32_t oldwords[8];
int useX = 1;
uint32_t openfolder = 0;
err = BLGetVolumeFinderInfo(context, actargs[kmount].argument, oldwords);
if(err) {
blesscontextprintf(context, kBLLogLevelError, "Error getting old Finder info words for %s\n", actargs[kmount].argument );
return 1;
}
if(actargs[ksave9].present) {
folder9id = oldwords[3];
blesscontextprintf(context, kBLLogLevelVerbose, "Saved folder 9\n" );
}
if(actargs[ksaveX].present) {
folderXid = oldwords[5];
blesscontextprintf(context, kBLLogLevelVerbose, "Saved folder X\n" );
}
if(actargs[kfolder].present) {
err = BLGetFileID(context, actargs[kfolder].argument, &folderXid);
if(err) {
blesscontextprintf(context, kBLLogLevelError, "Error while get directory ID of %s\n", actargs[kfolder].argument );
} else {
blesscontextprintf(context, kBLLogLevelVerbose, "Got directory ID of %u for %s\n",
folderXid, actargs[kfolder].argument );
}
}
if(actargs[kfolder9].present) {
err = BLGetFileID(context, actargs[kfolder9].argument, &folder9id);
if(err) {
blesscontextprintf(context, kBLLogLevelError, "Error while get directory ID of %s\n", actargs[kfolder9].argument );
} else {
blesscontextprintf(context, kBLLogLevelVerbose, "Got directory ID of %u for %s\n",
folder9id, actargs[kfolder9].argument );
}
}
if(actargs[kopenfolder].present) {
unsigned char openmount[kMaxArgLength];
openmount[0] = '\0';
err = BLGetCommonMountPoint(context, actargs[kopenfolder].argument,
actargs[kmount].argument, openmount);
if(err || strcmp(actargs[kmount].argument, openmount)) {
blesscontextprintf(context, kBLLogLevelError, "Error determining mountpoint of %s\n", actargs[kopenfolder].argument );
}
err = BLGetFileID(context, actargs[kopenfolder].argument, &openfolder);
if(err) {
blesscontextprintf(context, kBLLogLevelError, "Error while get directory ID of %s\n", actargs[kopenfolder].argument );
} else {
blesscontextprintf(context, kBLLogLevelVerbose, "Got directory ID of %u for %s\n",
openfolder, actargs[kopenfolder].argument );
}
}
if(actargs[kuse9].present) {
useX = 0;
}
oldwords[2] = openfolder;
oldwords[3] = folder9id;
oldwords[5] = folderXid;
if(!folderXid || !useX) {
oldwords[0] = folder9id;
} else {
oldwords[0] = folderXid;
}
blesscontextprintf(context, kBLLogLevelVerbose, "finderinfo[0] = %d\n", oldwords[0] );
blesscontextprintf(context, kBLLogLevelVerbose, "finderinfo[2] = %d\n", oldwords[2] );
blesscontextprintf(context, kBLLogLevelVerbose, "finderinfo[3] = %d\n", oldwords[3] );
blesscontextprintf(context, kBLLogLevelVerbose, "finderinfo[5] = %d\n", oldwords[5] );
err = BLSetVolumeFinderInfo(context, actargs[kmount].argument, oldwords);
if(err) {
blesscontextprintf(context, kBLLogLevelError, "Can't set Finder info fields for volume mounted at %s\n", actargs[kmount].argument );
return 2;
}
if(actargs[kbootblockfile].present) {
CFDataRef bbdata = NULL;
err = BLLoadFile(context, actargs[kbootblockfile].argument, 0, &bbdata);
if(err) {
blesscontextprintf(context, kBLLogLevelError, "Can't get boot blocks from data-fork file %s\n",
actargs[kbootblockfile].argument);
return 1;
} else {
blesscontextprintf(context, kBLLogLevelVerbose, "Boot blocks read from %s\n", actargs[kbootblockfile].argument );
}
err = BLSetBootBlocks(context, actargs[kmount].argument, bbdata);
CFRelease(bbdata);
if(err) {
blesscontextprintf(context, kBLLogLevelError, "Can't set boot blocks for %s\n", actargs[kmount].argument );
return 1;
} else {
blesscontextprintf(context, kBLLogLevelVerbose, "Boot blocks set successfully\n" );
}
}
}
if(actargs[ksetboot].present) {
if(BLIsOpenFirmwarePresent(context)) {
err = BLSetOpenFirmwareBootDeviceForMountPoint(context, actargs[kmount].argument);
if(err) {
blesscontextprintf(context, kBLLogLevelError, "Can't set Open Firmware\n" );
return 1;
} else {
blesscontextprintf(context, kBLLogLevelVerbose, "Open Firmware set successfully\n" );
}
} else {
struct statfs sb;
unsigned char parDev[MNAMELEN];
unsigned long slice;
BLPartitionType ptype;
CFDataRef bootconfigdata = NULL;
err = statfs(actargs[kmount].argument, &sb);
if(err) {
return 2;
}
err = BLGetParentDeviceAndPartitionType(context, sb.f_mntfromname, parDev, &slice, &ptype);
if(err) {
return 3;
}
blesscontextprintf(context, kBLLogLevelVerbose, "Mount point '%s' is part of an %s partition map\n",
actargs[kmount].argument,
ptype == kBLPartitionType_APM ? "Apple" : (ptype == kBLPartitionType_MBR ? "MBR" : "Unknown"));
if(ptype == kBLPartitionType_MBR) {
CFMutableDictionaryRef plist = NULL;
char ofstring[1024];
CFStringRef ofref;
unsigned char configpath[MAXPATHLEN+1];
snprintf(configpath, MAXPATHLEN, "%s/%s", actargs[kmount].argument, kBL_PATH_I386_BOOT2_CONFIG_PLIST);
err = BLLoadFile(context, configpath, 0, &bootconfigdata);
if(err) {
blesscontextprintf(context, kBLLogLevelVerbose, "Could not load boot2 config plist from %s\n", configpath);
blesscontextprintf(context, kBLLogLevelVerbose, "Using built-in default\n");
bootconfigdata = CFDataCreate(kCFAllocatorDefault, bootconfigplist, sizeof(bootconfigplist));
}
plist = (CFMutableDictionaryRef)CFPropertyListCreateFromXMLData(kCFAllocatorDefault, bootconfigdata, kCFPropertyListMutableContainers, NULL);
CFRelease(bootconfigdata);
if(plist == NULL || CFGetTypeID(plist) != CFDictionaryGetTypeID()) {
blesscontextprintf(context, kBLLogLevelError, "Could not parse boot config plist as dictionary\n");
if(plist) CFRelease(plist);
return 5;
}
err = BLGetOpenFirmwareBootDevice(context, sb.f_mntfromname, ofstring);
if(err) {
blesscontextprintf(context, kBLLogLevelError, "Could not map %s to an OpenFirmware path\n", sb.f_mntfromname);
CFRelease(plist);
return 6;
}
ofref = CFStringCreateWithCString(kCFAllocatorDefault, ofstring, kCFStringEncodingUTF8);
if(!ofref) {
CFRelease(plist);
return 7;
}
CFDictionaryAddValue(plist, CFSTR("Boot Device"), ofref);
CFRelease(ofref);
bootconfigdata = CFPropertyListCreateXMLData(kCFAllocatorDefault, plist);
CFRelease(plist);
if(!bootconfigdata) {
blesscontextprintf(context, kBLLogLevelError, "Could not convert dictionary to XML\n");
return 8;
}
err = BLCreateFile(context, bootconfigdata, actargs[kmount].argument, kBL_PATH_I386_BOOT2_CONFIG_PLIST,
0, 0, 0);
if(err) {
blesscontextprintf(context, kBLLogLevelError, "Could not write new %s\n", configpath);
CFRelease(bootconfigdata);
return 8;
}
CFRelease(bootconfigdata);
}
}
}
if((actargs[klabel].present||actargs[klabelfile].present) && isHFS) {
CFDataRef labeldata = NULL;
uint32_t oldwords2[8];
unsigned char sysfolder[MAXPATHLEN];
int isLabel = 0;
if(actargs[klabelfile].present) {
err = BLLoadFile(context, actargs[klabelfile].argument, 0, &labeldata);
if(err) {
blesscontextprintf(context, kBLLogLevelError, "Can't load label '%s'\n",
actargs[klabelfile].argument);
return 2;
}
}
isLabel = isOFLabel(CFDataGetBytePtr(labeldata),
CFDataGetLength(labeldata));
blesscontextprintf(context, kBLLogLevelVerbose, "OF label data is valid: %s\n", isLabel ? "YES" : "NO");
err = BLGetVolumeFinderInfo(context, actargs[kmount].argument, oldwords2);
if(err) {
blesscontextprintf(context, kBLLogLevelError, "Don't know where to generate bitmap\n" );
return 1;
}
err = BLLookupFileIDOnMount(context, actargs[kmount].argument, oldwords2[0], sysfolder);
if(err) {
return 2;
}
blesscontextprintf(context, kBLLogLevelVerbose, "Putting label bitmap in %s/%s\n", sysfolder, "Volume Name Icon" );
if(err) {
return 2;
}
err = BLCreateFile(context, (void *)labeldata,
sysfolder,
"Volume Name Icon",
0,
isLabel ? kBL_OSTYPE_PPC_TYPE_OFLABEL : 'xxxx',
kBL_OSTYPE_PPC_CREATOR_CHRP);
if(err) {
blesscontextprintf(context, kBLLogLevelError, "Could not write bitmap label file\n" );
CFRelease(labeldata);
return 1;
} else {
blesscontextprintf(context, kBLLogLevelVerbose, "OF label written\n");
}
CFRelease(labeldata);
strcat(sysfolder, "/Volume Name Icon");
err = BLSetFinderFlag(context, sysfolder, kIsInvisible, 1);
if(err) {
blesscontextprintf(context, kBLLogLevelError, "Could not set invisibility for %s\n", sysfolder );
return 1;
} else {
blesscontextprintf(context, kBLLogLevelVerbose, "Invisibility set for %s\n", sysfolder );
}
}
if(actargs[kxcoff].present && isHFS) {
if(actargs[kfolder].present) {
CFDataRef data = NULL;
uint32_t entrypoint, loadbase, size, checksum;
off_t extents[8][2];
unsigned char parent[MAXPATHLEN];
unsigned long pNum;
unsigned char sysfolder[MAXPATHLEN];
unsigned char command[2048];
unsigned char device[MNAMELEN];
strncpy(sysfolder, actargs[kfolder].argument, MAXPATHLEN-1);
sysfolder[MAXPATHLEN-1] = '\0';
err = BLLoadXCOFFLoader(context,
actargs[kxcoff].argument,
&entrypoint,
&loadbase,
&size,
&checksum,
&data);
if(err) {
blesscontextprintf(context, kBLLogLevelError, "Could not load XCOFF loader from %s\n", actargs[kxcoff].argument );
return 1;
}
blesscontextprintf(context, kBLLogLevelVerbose, "Creating loader BootX.image in %s\n", sysfolder );
err = BLCreateFile(context, data,
sysfolder,
"BootX.image",
0, 0, kBL_OSTYPE_PPC_CREATOR_CHRP);
CFRelease(data);
if(err) {
blesscontextprintf(context, kBLLogLevelError, "Error %d while creating BootX.image\n", err);
return 1;
}
strcat(sysfolder, "/BootX.image");
err = BLGetDiskSectorsForFile(context,
sysfolder,
extents,
device);
if(err) {
blesscontextprintf(context, kBLLogLevelError, "Error while finding BootX.image on disk\n", err);
return 1;
}
err = BLGetParentDevice(context, device, parent, &pNum);
if(err) {
parent[0] = '\0';
pNum = 0;
}
sprintf(command, "/usr/sbin/pdisk %s -makeBootable %lu %qd %u %u %u",
parent, pNum, extents[0][0], size, loadbase, entrypoint);
blesscontextprintf(context, kBLLogLevelVerbose, "pdisk command: %s\n", command);
blesscontextprintf(context, kBLLogLevelNormal, "%s\n", command);
} else {
blesscontextprintf(context, kBLLogLevelVerbose, "Could not create BootX.image, no X folder specified\n" );
}
}
return 0;
}
static int isOFLabel(const char *data, int labelsize)
{
uint16_t width, height;
if(data[0] != 1) return 0;
width = CFSwapInt16BigToHost(*(uint16_t *)&data[1]);
height = CFSwapInt16BigToHost(*(uint16_t *)&data[3]);
if(labelsize != (width*height+5)) return 0;
return 1;
}