/* Copyright (c) 2007 Peter O'Gorman * * 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 #include #include #include #include #include #include #include #include #include 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 \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; }