1/*
2 * Copyright (c) 2007 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23#include <libc.h>
24#include <errno.h>
25
26#include <sys/stat.h>
27#include <sys/file.h>
28#include <sys/mman.h>
29
30#include <mach-o/swap.h>
31
32#include <stdbool.h>
33
34/*********************************************************************
35*********************************************************************/
36static int
37writeFile(int fd, const void * data, size_t length)
38{
39    int error = 0;
40
41    if (length != (size_t)write(fd, data, length)) {
42        error = -1;
43    }
44
45    if (error != 0) {
46        perror("couldn't write output");
47    }
48
49    return error;
50}
51
52/*********************************************************************
53*********************************************************************/
54static int
55readFile(const char *path, vm_offset_t * objAddr, vm_size_t * objSize)
56{
57    int error = -1;
58    int fd;
59    struct stat stat_buf;
60
61    *objAddr = 0;
62    *objSize = 0;
63
64    do {
65        if ((fd = open(path, O_RDONLY)) == -1) {
66            continue;
67        }
68
69        if (fstat(fd, &stat_buf) == -1) {
70            continue;
71        }
72
73        if (0 == (stat_buf.st_mode & S_IFREG)) {
74            continue;
75        }
76
77        if (0 == stat_buf.st_size) {
78            error = 0;
79            continue;
80        }
81
82        *objSize = stat_buf.st_size;
83
84        *objAddr = (vm_offset_t)mmap(NULL /* address */, *objSize,
85            PROT_READ|PROT_WRITE, MAP_FILE|MAP_PRIVATE /* flags */,
86            fd, 0 /* offset */);
87
88        if ((void *)*objAddr == MAP_FAILED) {
89                *objAddr = 0;
90                *objSize = 0;
91            continue;
92        }
93
94        error = 0;
95
96    } while (false);
97
98    if (-1 != fd) {
99        close(fd);
100    }
101    if (error) {
102        fprintf(stderr, "couldn't read %s: %s\n", path, strerror(errno));
103    }
104
105    return error;
106}
107
108static void
109usage(void)
110{
111    fprintf(stderr, "Usage: %s [-s OLDSEGNAME] -n NEWSEGNAME input -o output\n", getprogname());
112    exit(1);
113}
114
115/*********************************************************************
116*********************************************************************/
117int main(int argc, char * argv[])
118{
119    int                     error;
120    const char            * output_name = NULL;
121    const char            * input_name = NULL;
122    const char            * oldseg_name = NULL;
123    const char            * newseg_name = NULL;
124    struct mach_header    * hdr;
125    struct mach_header_64 * hdr64;
126    struct load_command   * cmds;
127    boolean_t		        swap = false;
128    uint32_t		        ncmds, cmdtype;
129    uint32_t		        len;
130    vm_offset_t		        input;
131    vm_size_t		        input_size;
132    uint32_t		        nsects = 0;
133    uint32_t                * flags = NULL;
134    uint32_t		        attr;
135    typedef char            segname_t[16];
136    segname_t             * names = NULL;
137    int                     ch;
138
139
140    while ((ch = getopt(argc, argv, "s:n:o:")) != -1) {
141        switch (ch) {
142            case 's':
143                oldseg_name = optarg;
144                break;
145            case 'n':
146                newseg_name = optarg;
147                break;
148            case 'o':
149                output_name = optarg;
150                break;
151            case '?':
152            default:
153                usage();
154        }
155    }
156
157    argc -= optind;
158    argv += optind;
159
160	if ((argc != 1) || !newseg_name || !output_name) {
161        usage();
162    }
163
164    input_name = argv[0];
165
166    error = readFile(input_name, &input, &input_size);
167    if (error) {
168        exit(1);
169    }
170
171    hdr = (typeof(hdr)) input;
172    switch (hdr->magic) {
173        case MH_CIGAM:
174            swap = true;
175            // fall thru
176        case MH_MAGIC:
177            ncmds = hdr->ncmds;
178            cmds  = (typeof(cmds)) (hdr+1);
179            break;
180
181        case MH_CIGAM_64:
182            swap = true;
183            // fall thru
184        case MH_MAGIC_64:
185            hdr64 = (typeof(hdr64)) hdr;
186            ncmds = hdr64->ncmds;
187            cmds  = (typeof(cmds)) (hdr64+1);
188            break;
189
190        default:
191            fprintf(stderr, "not macho input file\n");
192            exit(1);
193            break;
194    }
195
196    if (swap) {
197        ncmds = OSSwapInt32(ncmds);
198    }
199    while (ncmds--) {
200        cmdtype = cmds->cmd;
201        if (swap) {
202            cmdtype = OSSwapInt32(cmdtype);
203        }
204        nsects = 0;
205        len    = 0;
206        if (LC_SEGMENT == cmdtype) {
207            struct segment_command * segcmd;
208            struct section         * sects;
209
210            segcmd = (typeof(segcmd)) cmds;
211            nsects = segcmd->nsects;
212            sects  = (typeof(sects))(segcmd + 1);
213            names  = &sects->segname;
214            flags  = &sects->flags;
215            len    = sizeof(*sects);
216        } else if (LC_SEGMENT_64 == cmdtype) {
217            struct segment_command_64 * segcmd;
218            struct section_64         * sects;
219
220            segcmd = (typeof(segcmd)) cmds;
221            nsects = segcmd->nsects;
222            sects  = (typeof(sects))(segcmd + 1);
223            names  = &sects->segname;
224            flags  = &sects->flags;
225            len    = sizeof(*sects);
226        }
227
228        if (swap)
229            nsects = OSSwapInt32(nsects);
230        while (nsects--) {
231            attr = *flags;
232            if (swap) {
233                attr = OSSwapInt32(attr);
234            }
235
236            if (!(S_ATTR_DEBUG & attr)) {
237                if (!oldseg_name ||
238                    0 == strncmp(oldseg_name, (char *)names, sizeof(*names))) {
239                    memset(names, 0x0, sizeof(*names));
240                    strncpy((char *)names, newseg_name, sizeof(*names));
241                }
242            }
243
244            names = (typeof(names))(((uintptr_t) names) + len);
245            flags = (typeof(flags))(((uintptr_t) flags) + len);
246        }
247
248        len = cmds->cmdsize;
249        if (swap) {
250            len = OSSwapInt32(len);
251        }
252        cmds = (typeof(cmds))(((uintptr_t) cmds) + len);
253    }
254
255    int fd = open(output_name, O_WRONLY|O_CREAT|O_TRUNC, 0755);
256    if (-1 == fd) {
257        error = -1;
258    } else {
259        error = writeFile(fd, (const void *) input, input_size);
260        close(fd);
261    }
262
263    if (error) {
264        fprintf(stderr, "couldn't write output: %s\n", strerror(errno));
265        exit(1);
266    }
267
268    exit(0);
269    return 0;
270}
271