#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <paths.h>
#include <sys/stat.h>
#include <sys/mount.h>
#include <sys/paths.h>
#include <string.h>
#include <APFS/APFS.h>
#include "enums.h"
#include "structs.h"
#include "bless.h"
#include "bless_private.h"
#include "protos.h"
int modeDevice(BLContextPtr context, struct clarg actargs[klast]) {
int ret = 0;
CFDataRef labeldata = NULL;
CFDataRef labeldata2 = NULL;
CFDataRef bootXdata = NULL;
io_object_t devMediaObj;
BLPreBootEnvType preboot;
if(!(geteuid() == 0)) {
blesscontextprintf(context, kBLLogLevelError, "Not run as root\n" );
return 1;
}
ret = BLGetPreBootEnvironmentType(context, &preboot);
if(ret) {
blesscontextprintf(context, kBLLogLevelError, "Could not determine preboot environment\n");
return 1;
}
if(actargs[klabelfile].present) {
ret = BLLoadFile(context, actargs[klabelfile].argument, 0, &labeldata);
if(ret) {
blesscontextprintf(context, kBLLogLevelError, "Can't load label '%s'\n",
actargs[klabelfile].argument);
return 2;
}
} else if(actargs[klabel].present) {
ret = BLGenerateLabelData(context, actargs[klabel].argument, kBitmapScale_1x, &labeldata);
if(ret) {
blesscontextprintf(context, kBLLogLevelError, "Can't render scale 1 label '%s'\n",
actargs[klabel].argument);
return 3;
}
ret = BLGenerateLabelData(context, actargs[klabel].argument, kBitmapScale_2x, &labeldata2);
if(ret) {
blesscontextprintf(context, kBLLogLevelError, "Can't render scale 2 label '%s'\n",
actargs[klabel].argument);
return 3;
}
}
if(actargs[kbootinfo].present) {
if(!actargs[kbootinfo].hasArg) {
blesscontextprintf(context, kBLLogLevelError,
"BootX file must be specified in Device Mode\n");
return 4;
}
ret = BLLoadFile(context, actargs[kbootinfo].argument, 0, &bootXdata);
if(ret) {
blesscontextprintf(context, kBLLogLevelError, "Could not load BootX data from %s\n",
actargs[kbootinfo].argument);
}
}
devMediaObj = IOServiceGetMatchingService(kIOMasterPortDefault, IOBSDNameMatching(kIOMasterPortDefault, 0,
actargs[kdevice].argument + strlen(_PATH_DEV)));
if (!devMediaObj) {
blesscontextprintf(context, kBLLogLevelError, "Couldn't find I/O Registry information for device %s\n", actargs[kdevice].argument);
return 4;
}
if (IOObjectConformsTo(devMediaObj, APFS_VOLUME_OBJECT)) {
ret = BlessPrebootVolume(context, actargs[kdevice].argument + strlen(_PATH_DEV), NULL, NULL, NULL,
actargs);
}
IOObjectRelease(devMediaObj);
if (ret) {
blesscontextprintf(context, kBLLogLevelError, "Couldn't set bless data in preboot volume for device %s\n", actargs[kdevice].argument);
return 5;
}
if(actargs[ksetboot].present) {
if(preboot == kBLPreBootEnvType_EFI) {
ret = setefidevice(context, actargs[kdevice].argument + strlen("/dev/"),
actargs[knextonly].present,
actargs[klegacy].present,
actargs[klegacydrivehint].present ? actargs[klegacydrivehint].argument : NULL,
actargs[koptions].present ? actargs[koptions].argument : NULL,
actargs[kshortform].present ? true : false);
} else {
ret = setboot(context, actargs[kdevice].argument, bootXdata, labeldata);
}
if(ret) {
return 3;
}
} else if (labeldata) {
ret = BLSetDiskLabelForDevice(context, actargs[kdevice].argument, labeldata, 1);
if(ret) {
blesscontextprintf(context, kBLLogLevelError, "Error while setting scale 1 label for %s\n", actargs[kdevice].argument );
return 3;
}
if (labeldata2) {
ret = BLSetDiskLabelForDevice(context, actargs[kdevice].argument, labeldata2, 2);
if(ret) {
blesscontextprintf(context, kBLLogLevelError, "Error while setting scale 2 label for %s\n", actargs[kdevice].argument );
return 3;
}
}
}
if (labeldata) CFRelease(labeldata);
if (labeldata2) CFRelease(labeldata2);
if (bootXdata) CFRelease(bootXdata);
return 0;
}