Skip to content

Instantly share code, notes, and snippets.

@atr000
Created August 20, 2010 22:20
Show Gist options
  • Select an option

  • Save atr000/541320 to your computer and use it in GitHub Desktop.

Select an option

Save atr000/541320 to your computer and use it in GitHub Desktop.
/* Copyright (c) 2007 Peter O'Gorman <peter@pogma.com>
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use, copy,
* modify, merge, publish, distribute, sublicense, and/or sell copies
* of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include <sys/types.h>
#include <inttypes.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <stdio.h>
#include <unistd.h>
#include <mach-o/fat.h>
#include <mach-o/loader.h>
#include <stdlib.h>
#include <sys/errno.h>
uint32_t cur_ver = 0;
uint32_t com_ver = 0;
int swap=0;
/* This function stolen from Apple's ld64 sources - licensed APSL */
uint32_t version_num(const char * string)
{
unsigned long x = 0;
unsigned long y = 0;
unsigned long z = 0;
char* end;
x = strtoul(string, &end, 10);
if ( *end == '.' ) {
y = strtoul(&end[1], &end, 10);
if ( *end == '.' ) {
z = strtoul(&end[1], &end, 10);
}
}
return (x << 16) | ( y << 8 ) | z;
}
void adjust_version(struct mach_header * in)
{
char * pointer;
int x = in->ncmds;
if ((in->magic == MH_MAGIC) || (in->magic == MH_CIGAM))
pointer = (char*)in + sizeof(struct mach_header);
else if ((in->magic == MH_MAGIC_64) || (in->magic == MH_CIGAM_64))
pointer = (char*)in + sizeof(struct mach_header_64);
else {fprintf(stderr,"dead\n"); exit(1);}
if ((in->magic == MH_CIGAM) || (in->magic == MH_CIGAM_64))
swap=1;
else swap=0;
if (swap) {
x=OSSwapInt32(in->ncmds);
}
do {
if (swap) {
if (LC_ID_DYLIB == OSSwapInt32(((struct load_command *)pointer)->cmd)) {
pointer += sizeof(struct load_command);
((struct dylib *)pointer)->current_version = OSSwapInt32(cur_ver);
((struct dylib *)pointer)->compatibility_version = OSSwapInt32(com_ver);
x = 0;
} else {
pointer += OSSwapInt32(((struct load_command *)pointer)->cmdsize);
x--;
}
} else {
if (LC_ID_DYLIB == ((struct load_command *)pointer)->cmd) {
pointer += sizeof(struct load_command);
((struct dylib *)pointer)->current_version = cur_ver;
((struct dylib *)pointer)->compatibility_version = com_ver;
x = 0;
} else {
pointer += ((struct load_command *)pointer)->cmdsize;
x--;
}
}
} while (x);
}
void usage(void) {
fprintf(stderr,"Usage:\n%s <filename> <compatibility_version> <current_version>\n",getprogname());
}
int main(int argc, const char * argv[])
{
int fd = 0;
ssize_t bytesread = 0;
size_t bytes = 0;
struct stat sbuf;
void * buffer;
if (argc != 4) {
fprintf(stderr,"Incorrect number of arguments\n");
usage();
exit(1);
}
if (stat(argv[1],&sbuf)) {
fprintf(stderr,"File does not exist\n");
usage();
exit(1);
}
com_ver = version_num(argv[2]);
cur_ver = version_num(argv[3]);
if (!(fd = open(argv[1],O_RDWR | O_EXCL ,sbuf.st_mode))) {
fprintf(stderr,"OPen failed %s\n",strerror(errno));
exit (1);
}
bytes = sbuf.st_size;
buffer = malloc(bytes);
if (!buffer) {
fprintf(stderr,"Failed to allocate %d bytes\n",bytes);
exit(1);
}
do {
bytesread = read(fd,buffer,bytes);
if (bytesread == -1) {
fprintf(stderr,"Error %s\n",strerror(errno));
exit(1);
}
else if (bytesread == 0)
bytes = 0;
else
bytes -= bytesread;
} while (bytes);
if (lseek(fd,0,SEEK_SET)) {
fprintf(stderr,"Failed to seek to beginning of file\n");
exit(1);
}
if ((((struct fat_header*)buffer)->magic == FAT_MAGIC) ||
(((struct fat_header*)buffer)->magic == FAT_CIGAM)) {
struct fat_header * fh = (struct fat_header*)buffer;
uint32_t num_arches = fh->nfat_arch;
struct fat_arch * arch= (struct fat_arch *)((char*)buffer + sizeof(struct fat_header));
#ifdef __LITTLE_ENDIAN__
num_arches = OSSwapInt32(fh->nfat_arch);
#endif
do {
#ifdef __LITTLE_ENDIAN__
adjust_version((struct mach_header*)((char*)buffer + OSSwapInt32(arch->offset)));
#else
adjust_version((struct mach_header*)((char*)buffer + arch->offset));
#endif
arch++;
num_arches--;
} while(num_arches);
} else
adjust_version(buffer);
bytes = 0;
do {
bytes += write(fd,buffer,sbuf.st_size - bytes);
} while (sbuf.st_size - bytes);
if (fd) close(fd);
fd = 0;
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment