Index: trunk/doc/BootHelp.txt =================================================================== --- trunk/doc/BootHelp.txt (revision 412) +++ trunk/doc/BootHelp.txt (revision 413) @@ -48,14 +48,18 @@ "Instant Menu"=Yes Force displaying the partition selection menu. "Default Partition" Sets the default boot partition, - =hd(x,y)| where 'x' & 'y' are the disk and partition numbers - = or specify the selected volume UUID string. + =hd(x,y)|UUID|"Label" Specified as a disk/partition pair, an UUID, or a + label enclosed in quotes. + "Hide Partition" Remove unwanted partition(s) from the boot menu. - =hd(x,y) [hd(m,n)] only non mac osx boot partitions can be hidden. + =partition Specified, possibly multiple times, as hd(x,y), an + [;partition2 ...] UUID or label enclosed in quotes. + + "Rename Partition" Rename partition(s) for the boot menu. + =partition Where partition is hd(x,y), UUID or label enclosed + [;partition2 in quotes. The alias can optionally be quoted too. + ...] - "Rename Partition" Rename partition(s) for the boot menu. - =hd(x,y) [;hd(m,n) ...] - GUI=No Disable the GUI (enabled by default). "Boot Banner"=Yes|No Show boot banner in GUI mode (enabled by default). "Legacy Logo"=Yes|No Use the legacy grey apple logo (disabled by default). Index: trunk/Chameleon.xcodeproj/project.pbxproj =================================================================== --- trunk/Chameleon.xcodeproj/project.pbxproj (revision 412) +++ trunk/Chameleon.xcodeproj/project.pbxproj (revision 413) @@ -10,6 +10,7 @@ 0172D0DC11FB66820030222E /* dram_controllers.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = dram_controllers.h; sourceTree = ""; }; 0172D0DD11FB66820030222E /* dram_controllers.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = dram_controllers.c; sourceTree = ""; }; 019DFBAF11FB94090013E8CC /* MEMTEST86_LICENSE */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = MEMTEST86_LICENSE; sourceTree = ""; }; + 65ED53931204B83200B22507 /* disk.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = disk.h; sourceTree = ""; }; B0056CD611F3868000754B65 /* boot */ = {isa = PBXFileReference; lastKnownFileType = text; path = boot; sourceTree = ""; }; B0056CD711F3868000754B65 /* boot.sys */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.preload"; path = boot.sys; sourceTree = ""; }; B0056CD811F3868000754B65 /* boot0 */ = {isa = PBXFileReference; lastKnownFileType = text; path = boot0; sourceTree = ""; }; @@ -497,6 +498,7 @@ B0056D3911F3868000754B65 /* device_tree.c */, B0056D3A11F3868000754B65 /* device_tree.h */, B0056D3B11F3868000754B65 /* disk.c */, + 65ED53931204B83200B22507 /* disk.h */, 0172D0DC11FB66820030222E /* dram_controllers.h */, 0172D0DD11FB66820030222E /* dram_controllers.c */, B0056D3C11F3868000754B65 /* efi.h */, Index: trunk/i386/libsaio/xml.c =================================================================== --- trunk/i386/libsaio/xml.c (revision 412) +++ trunk/i386/libsaio/xml.c (revision 413) @@ -110,7 +110,64 @@ return 0; } +/* Function for basic XML character entities parsing */ +char* +XMLDecode(const char* src) +{ + typedef const struct XMLEntity { + const char* name; + size_t nameLen; + char value; + } XMLEntity; + + /* This is ugly, but better than specifying the lengths by hand */ + #define _e(str,c) {str,sizeof(str)-1,c} + const XMLEntity ents[] = { + _e("quot;",'"'), _e("apos;",'\''), + _e("lt;", '<'), _e("gt;", '>'), + _e("amp;", '&') + }; + + size_t len; + const char *s; + char *out, *o; + + if ( !src || !(len = strlen(src)) || !(out = malloc(len+1)) ) + return 0; + + o = out; + s = src; + while (s <= src+len) /* Make sure the terminator is also copied */ + { + if ( *s == '&' ) + { + bool entFound = false; + int i; + + s++; + for ( i = 0; i < sizeof(ents); i++) + { + if ( strncmp(s, ents[i].name, ents[i].nameLen) == 0 ) + { + entFound = true; + break; + } + } + if ( entFound ) + { + *o++ = ents[i].value; + s += ents[i].nameLen; + continue; + } + } + + *o++ = *s++; + } + + return out; +} + #if UNUSED //========================================================================== // XMLParseFile Index: trunk/i386/libsaio/xml.h =================================================================== --- trunk/i386/libsaio/xml.h (revision 412) +++ trunk/i386/libsaio/xml.h (revision 413) @@ -73,6 +73,7 @@ TagPtr XMLGetProperty( TagPtr dict, const char * key ); long XMLParseNextTag(char *buffer, TagPtr *tag); void XMLFreeTag(TagPtr tag); +char* XMLDecode(const char *in); //========================================================================== // XMLParseFile // Expects to see one dictionary in the XML file. Index: trunk/i386/libsaio/ntfs_private.h =================================================================== --- trunk/i386/libsaio/ntfs_private.h (revision 412) +++ trunk/i386/libsaio/ntfs_private.h (revision 413) @@ -275,8 +275,10 @@ cn_t bf_mftmirrcn; /* $MFTMirr cn */ u_int8_t bf_mftrecsz; /* MFT record size (clust) */ /* 0xF6 inducates 1/4 */ - u_int32_t bf_ibsz; /* index buffer size */ - u_int32_t bf_volsn; /* volume ser. num. */ + u_int8_t reserved5[3]; + u_int8_t bf_ibsz; /* index buffer size */ + u_int8_t reserved6[3]; + u_int64_t bf_volsn; /* volume ser. num. */ }; /* Index: trunk/i386/libsaio/ntfs.c =================================================================== --- trunk/i386/libsaio/ntfs.c (revision 412) +++ trunk/i386/libsaio/ntfs.c (revision 413) @@ -295,6 +295,41 @@ return; } +long NTFSGetUUID(CICell ih, char *uuidStr) +{ + bool NTFSProbe(const void*); + + struct bootfile *boot; + void *buf = malloc(MAX_BLOCK_SIZE); + if ( !buf ) + return -1; + + /* + * Read the boot sector, check signatures, and do some minimal + * sanity checking. NOTE: the size of the read below is intended + * to be a multiple of all supported block sizes, so we don't + * have to determine or change the device's block size. + */ + Seek(ih, 0); + Read(ih, (long)buf, MAX_BLOCK_SIZE); + + boot = (struct bootfile *) buf; + + // Check for NTFS signature + if ( memcmp((void*)boot->bf_sysid, NTFS_BBID, NTFS_BBIDLEN) != 0 ) + return -1; + + // Check for non-null volume serial number + if( !boot->bf_volsn ) + return -1; + + // Use UUID like the one you get on Windows + return sprintf(uuidStr, "%04X-%04X", (unsigned short)(boot->bf_volsn >> 16) & 0xFFFF, + (unsigned short)boot->bf_volsn & 0xFFFF); + + // return CreateUUIDString((uint8_t*)&(boot->bf_volsn), sizeof(boot->bf_volsn), uuidStr); +} + bool NTFSProbe(const void * buffer) { bool result = false; @@ -307,5 +342,3 @@ return result; } - - Index: trunk/i386/libsaio/sys.c =================================================================== --- trunk/i386/libsaio/sys.c (revision 412) +++ trunk/i386/libsaio/sys.c (revision 413) @@ -63,7 +63,9 @@ #include "libsaio.h" #include "boot.h" #include "bootstruct.h" +#include "disk.h" #include "ramdisk.h" +#include "xml.h" #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5 # include #else @@ -819,33 +821,21 @@ return bvr; /* - * Checking "Default Partition" key in system configuration - use format: hd(x,y) or the volume UUID - + * Checking "Default Partition" key in system configuration - use format: hd(x,y), the volume UUID or label - * to override the default selection. * We accept only kBVFlagSystemVolume or kBVFlagForeignBoot volumes. */ - const char * val; - char testStr[64]; - int cnt; + char *val = XMLDecode(getStringForKey(kDefaultPartition, &bootInfo->bootConfig)); + if (val) { + for ( bvr = chain; bvr; bvr = bvr->next ) { + if (matchVolumeToString(bvr, val, false)) { + free(val); + return bvr; + } + } + free(val); + } - if (getValueForKey(kDefaultPartition, &val, &cnt, &bootInfo->bootConfig) && cnt >= 7 && filteredChain) - { - for ( bvr = chain; bvr; bvr = bvr->next ) - { - if ( bvr->biosdev >= 0x80 && bvr->biosdev < 0x100 - && ( bvr->flags & ( kBVFlagSystemVolume|kBVFlagForeignBoot ) ) ) - { - // Trying to match hd(x,y) format. - sprintf(testStr, "hd(%d,%d)", bvr->biosdev - 0x80, bvr->part_no); - if (strcmp(testStr, val) == 0) - return bvr; - - // Trying to match volume UUID. - if (bvr->fs_getuuid && bvr->fs_getuuid(bvr, testStr) == 0 && strcmp(testStr, val) == 0) - return bvr; - } - } - } - /* * Scannig the volume chain backwards and trying to find * a HFS+ volume with valid boot record signature. @@ -1075,20 +1065,24 @@ //========================================================================== // getDeviceDescription() - Extracts unit number and partition number // from bvr structure into "dw(u,p)" format. +// Returns length of the out string int getDeviceDescription(BVRef bvr, char *str) { - const struct devsw *dp; - + if(!str) + return 0; + *str = '\0'; if (bvr) { - for (dp = devsw; dp->name && bvr->biosdev >= dp->biosdev; dp++); + const struct devsw *dp = devsw; + while(dp->name && bvr->biosdev >= dp->biosdev) + dp++; + dp--; - if (dp->name) sprintf(str, "%s(%d,%d)", dp->name, bvr->biosdev - dp->biosdev, bvr->part_no); - - return true; + if (dp->name) + return sprintf(str, "%s(%d,%d)", dp->name, bvr->biosdev - dp->biosdev, bvr->part_no); } - return false; + return 0; } Index: trunk/i386/libsaio/ntfs.h =================================================================== --- trunk/i386/libsaio/ntfs.h (revision 412) +++ trunk/i386/libsaio/ntfs.h (revision 413) @@ -22,4 +22,4 @@ extern void NTFSGetDescription(CICell ih, char *str, long strMaxLen); extern bool NTFSProbe (const void *buf); - +extern long NTFSGetUUID(CICell ih, char *uuidStr); Index: trunk/i386/libsaio/disk.c =================================================================== --- trunk/i386/libsaio/disk.c (revision 412) +++ trunk/i386/libsaio/disk.c (revision 413) @@ -67,6 +67,9 @@ #include "msdos.h" #include "ext2fs.h" +#include "xml.h" +#include "disk.h" + #include #include #include @@ -870,7 +873,8 @@ biosdev, partno, part->relsect, part, - 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + NTFSGetUUID, NTFSGetDescription, (BVFree)free, 0, kBIOSDevTypeHardDrive, 0); @@ -1552,9 +1556,15 @@ struct DiskBVMap * map = NULL; int bvCount = 0; - const char *val; - char devsw[12]; + const char *raw = 0; + char* val = 0; int len; + + getValueForKey(kHidePartition, &raw, &len, &bootInfo->bootConfig); + if(raw) + { + val = XMLDecode(raw); + } /* * Traverse gDISKBVmap to get references for @@ -1587,18 +1597,14 @@ ) newBVR->visible = true; - /* - * Looking for "Hide Partition" entries in "hd(x,y) hd(n,m)" format + /* Looking for "Hide Partition" entries in 'hd(x,y)|uuid|"label" hd(m,n)|uuid|"label"' format * to be able to hide foreign partitions from the boot menu. */ - if ( (newBVR->flags & kBVFlagForeignBoot) - && getValueForKey(kHidePartition, &val, &len, &bootInfo->bootConfig) - ) - { - sprintf(devsw, "hd(%d,%d)", BIOS_DEV_UNIT(newBVR), newBVR->part_no); - if (strstr(val, devsw) != NULL) - newBVR->visible = false; - } + if ( (newBVR->flags & kBVFlagForeignBoot) ) + { + if(val && matchVolumeToString(newBVR, val, true)) + newBVR->visible = false; + } /* * Use the first bvr entry as the starting chain pointer. @@ -1627,6 +1633,8 @@ #endif *count = bvCount; + + free(val); return chain; } @@ -1677,75 +1685,204 @@ //========================================================================== +char* matchVolumeToString( BVRef bvr, const char* match, bool matchParcial) +{ + char testStr[64]; + char *ret = 0; + int len = 0; + + if ( !bvr || !match || !*match) + return 0; + + if ( bvr->biosdev < 0x80 || bvr->biosdev >= 0x100 + || !(bvr->flags & (kBVFlagSystemVolume|kBVFlagForeignBoot)) ) + return 0; + + // Try to match hd(x,y) first. + len = snprintf(testStr, sizeof(testStr)-1, "hd(%d,%d)", BIOS_DEV_UNIT(bvr), bvr->part_no); + if ( matchParcial ) + ret = strstr(match, testStr); + else if ( !strcmp(match, testStr) ) + ret = (char*) match; + if(ret) + return ret+len; + + + // Try to match volume UUID. + if ( bvr->fs_getuuid && bvr->fs_getuuid(bvr, testStr) == 0 ) + { + { + char* temp = malloc(64); + if(temp && bvr->description) { + bvr->description(bvr, temp, 63); + printf("Volume: UUID=%s, Label=%s\n", testStr, temp); + } + } + + len = strlen(testStr); + if ( matchParcial ) + ret = strstr(match, testStr); + else if ( !strcmp(match, testStr) ) + ret = (char*) match; + if(ret) + return ret+len; + } + + // Try to match volume label (always quoted). + if ( bvr->description ) + { + char *temp = 0; + + bvr->description(bvr, testStr, sizeof(testStr)-1); + len = strlen(testStr); + if ( !len ) + return 0; + + len += 2; /* quoted */ + temp = malloc(len+1); + + if(temp) + { + len = snprintf(temp, len, "\"%s\"", testStr); + if ( matchParcial ) + ret = strstr(match, temp); + else if ( !strcmp(match, temp) ) + ret = (char*) match; + + free(temp); + if (ret) + return ret+len; + } + } + + return 0; +} + /* If Rename Partition has defined an alias, then extract it for description purpose */ -static const char * getVolumeLabelAlias( BVRef bvr, const char * str, long strMaxLen) +bool getVolumeLabelAlias( BVRef bvr, char* str, long strMaxLen) { - const int MAX_ALIAS_SIZE=31; - static char szAlias[MAX_ALIAS_SIZE+1]; - char *q=szAlias; - const char * szAliases = getStringForKey(kRenamePartition, &bootInfo->bootConfig); + /* The format for the rename string is the following: + * hd(x,y)|uuid|"label" "alias";hd(m,n)|uuid|"label" etc; ... + */ + char *aliasList, *next; + + if ( !str || strMaxLen <= 0) + return false; + + aliasList = XMLDecode(getStringForKey(kRenamePartition, &bootInfo->bootConfig)); + if ( !aliasList ) + return false; + + next = aliasList; + while ( next && *next ) + { + char *start, *aliasStart, *aliasEnd; + char *ret; + + start = aliasStart = (char*)matchVolumeToString(bvr, next, true); + if ( !start || !*start ) + break; + + /* Find and delimit the current entry's end */ + next = strstr(start, ";"); + if ( next ) + { + /* Not enough characters for a successful match: we'd need at least + * one space and another char. before the semicolon + */ + if ( next-start < 2 ) { + next++; + continue; + } + + *next = '\0'; + next++; + } + + /* Check for at least one space, but ignore the rest of them */ + while ( isspace(*aliasStart) ) + aliasStart++; + if ( start == aliasStart ) + continue; - if (!str || !*str || !szAliases) return 0; // no renaming wanted - - const char * p = strstr(szAliases, str); - if(!p || !(*p)) return 0; // this volume must not be renamed, or option is malformed - - p+= strlen(str); // skip the "hd(n,m) " field - // multiple aliases can be found separated by a semi-column - while(*p && *p != ';' && q<(szAlias+MAX_ALIAS_SIZE)) *q++=*p++; - *q='\0'; - - return szAlias; + switch ( *aliasStart ) + { + case '\0': + break; + case '"': + /* If a starting quote is found, skip it, then find the ending one, + * and replace it for a string terminator. + */ + aliasStart++; + aliasEnd = strstr(aliasStart, "\""); + if ( !aliasEnd || aliasStart == aliasEnd ) + break; + + *aliasEnd = '\0'; + default: + ret = strncpy(str, aliasStart, strMaxLen); + free(aliasList); + + return ret != 0; + } + } + + free(aliasList); + return false; } -void getBootVolumeDescription( BVRef bvr, char * str, long strMaxLen, bool verbose ) +void getBootVolumeDescription( BVRef bvr, char * str, long strMaxLen, bool useDeviceDescription ) { - unsigned char type = (unsigned char) bvr->part_type; - char *p; + unsigned char type; + char *p = str; + + if(!bvr || !p || strMaxLen <= 0) + return; + + type = (unsigned char) bvr->part_type; + + if (useDeviceDescription) + { + int len = getDeviceDescription(bvr, str); + if(len >= strMaxLen) + return; + + len++; + strcpy(str + len, " "); + strMaxLen -= len; + p += len; + } - p = str; - if (verbose) { - getDeviceDescription(bvr, str); - strcat(str, " "); - for (; strMaxLen > 0 && *p != '\0'; p++, strMaxLen--); + /* See if a partition rename is preferred */ + if(getVolumeLabelAlias(bvr, p, strMaxLen)) { + verbose("Renamed: %s\n", p); + strncpy(bvr->label, p, sizeof(bvr->label) - 1); + return; // we're done here no need to seek for real name } - - // See if we should get the renamed alias name for this partion: - const char * szAliasName = getVolumeLabelAlias(bvr, str, strMaxLen); - if (szAliasName && *szAliasName) - { - strncpy(bvr->label, szAliasName, strMaxLen); - return; // we're done here no need to seek for real name - } // // Get the volume label using filesystem specific functions // or use the alternate volume label if available. // - if (*bvr->altlabel == '\0') - { - if (bvr->description) + if (*bvr->altlabel != '\0') + strncpy(p, bvr->altlabel, strMaxLen); + else if (bvr->description) bvr->description(bvr, p, strMaxLen); - } - else - strncpy(p, bvr->altlabel, strMaxLen); if (*p == '\0') { - const char * name = getNameForValue( fdiskTypes, type ); - if (name == NULL) { - name = bvr->type_name; - } - if (name == NULL) { - sprintf(p, "TYPE %02x", type); - } else { - strncpy(p, name, strMaxLen); - } + const char * name = getNameForValue( fdiskTypes, type ); + if (name == NULL) { + name = bvr->type_name; + } + if (name == NULL) { + sprintf(p, "TYPE %02x", type); + } else { + strncpy(p, name, strMaxLen); + } } - - /* See if a partion rename is wanted: */ - + // Set the devices label - sprintf(bvr->label, p); + strncpy(bvr->label, p, sizeof(bvr->label)-1); } //========================================================================== Index: trunk/i386/libsaio/saio_types.h =================================================================== --- trunk/i386/libsaio/saio_types.h (revision 412) +++ trunk/i386/libsaio/saio_types.h (revision 413) @@ -135,7 +135,7 @@ typedef long (*FSGetDirEntry)(CICell ih, char * dirPath, long long * dirIndex, char ** name, long * flags, long * time, FinderInfo * finderInfo, long * infoValid); -typedef long (* FSGetUUID)(CICell ih, char *uuidStr); +typedef long (*FSGetUUID)(CICell ih, char *uuidStr); typedef void (*BVGetDescription)(CICell ih, char * str, long strMaxLen); // Can be just pointed to free or a special free function typedef void (*BVFree)(CICell ih); Index: trunk/i386/boot2/options.c =================================================================== --- trunk/i386/boot2/options.c (revision 412) +++ trunk/i386/boot2/options.c (revision 413) @@ -111,7 +111,7 @@ position_t p = pos( gui.screen.width / 2 + 1 , ( gui.devicelist.pos.y + 3 ) + ( ( gui.devicelist.height - gui.devicelist.iconspacing ) / 2 ) ); char dummy[80]; - getBootVolumeDescription( gBootVolume, dummy, 80, true ); + getBootVolumeDescription( gBootVolume, dummy, sizeof(dummy) - 1, true ); drawDeviceIcon( gBootVolume, gui.screen.pixmap, p, true ); drawStrCenteredAt( (char *) msg, &font_small, gui.screen.pixmap, gui.countdown.pos ); @@ -781,7 +781,7 @@ strlcpy(prompt, val, cnt); } else { name = malloc(80); - getBootVolumeDescription(gBootVolume, name, 80, false); + getBootVolumeDescription(gBootVolume, name, sizeof(name) - 1, false); prompt = malloc(256); sprintf(prompt, "Press any key to start up from %s, or press F8 to enter startup options.", name); free(name); @@ -858,7 +858,7 @@ // Associate a menu item for each BVRef. for (bvr=bvChain, i=gDeviceCount-1, selectIndex=0; bvr; bvr=bvr->next) { if (bvr->visible) { - getBootVolumeDescription(bvr, menuItems[i].name, 80, true); + getBootVolumeDescription(bvr, menuItems[i].name, sizeof(menuItems[0].name) - 1, true); menuItems[i].param = (void *) bvr; if (bvr == menuBVR) { selectIndex = i; Index: trunk/i386/libsa/libsa.h =================================================================== --- trunk/i386/libsa/libsa.h (revision 412) +++ trunk/i386/libsa/libsa.h (revision 413) @@ -132,6 +132,7 @@ * printf.c */ extern int sprintf(char *s, const char * format, ...); +extern int snprintf(char *s, long len, const char* fmt, ...); extern int slvprintf(char * buffer, int len, const char * fmt, va_list arg); /* Index: trunk/i386/libsa/printf.c =================================================================== --- trunk/i386/libsa/printf.c (revision 412) +++ trunk/i386/libsa/printf.c (revision 413) @@ -60,6 +60,20 @@ return (pi.str - str); } +int snprintf(char *str, long len, const char * fmt, ...) +{ + va_list ap; + struct putc_info pi; + + va_start(ap, fmt); + pi.str = str; + pi.last_str = str + len - 1; + prf(fmt, ap, sputc, &pi); + *pi.str = '\0'; + va_end(ap); + return (pi.str - str); +} + /*VARARGS1*/ int slvprintf(char * str, int len, const char * fmt, va_list ap) {