Dump kernel and initrd from an Android boot image.
[cascardo/bootimg.git] / bootimg.c
1 /*
2  *  Copyright (C) 2014  Thadeu Lima de Souza Cascardo <cascardo@cascardo.eti.br>
3  *
4  *  This program is free software; you can redistribute it and/or modify
5  *  it under the terms of the GNU General Public License as published by
6  *  the Free Software Foundation; either version 3 of the License, or
7  *  (at your option) any later version.
8  *
9  *  This program is distributed in the hope that it will be useful,
10  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
11  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  *  GNU General Public License for more details.
13  *
14  *  You should have received a copy of the GNU General Public License along
15  *  with this program; if not, write to the Free Software Foundation, Inc.,
16  *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17  */
18
19 #include <stdint.h>
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <string.h>
23 #include <fcntl.h>
24 #include <unistd.h>
25 #include <errno.h>
26
27 static int dump(int fd, size_t len, int pgsz, char *fname)
28 {
29         int out;
30         char *page;
31         int i, npages;
32         int r;
33         page = malloc(pgsz);
34         if (!page)
35                 return -ENOMEM;
36         out = open(fname, O_WRONLY | O_CREAT | O_EXCL, 0644);
37         if (out < 0)
38                 return -errno;
39         npages = (len + pgsz - 1) / pgsz;
40         for (i = 1; i <= npages; i++) {
41                 if (i == npages) {
42                         len = len & (pgsz - 1);
43                         if (len > 0) {
44                                 r = read(fd, page, len);
45                                 if (r != len)
46                                         goto out;
47                                 r = write(out, page, len);
48                                 if (r != len)
49                                         goto out;
50                         }
51                 }
52                 r = read(fd, page, pgsz);
53                 if (r != pgsz)
54                         goto out;
55                 r = write(out, page, pgsz);
56                 if (r != pgsz)
57                         goto out;
58         }
59         free(page);
60         close(out);
61         return 0;
62 out:
63         free(page);
64         close(out);
65         if (r < 0)
66                 return -errno;
67         return -EINVAL;
68 }
69
70 int main(int argc, char **argv)
71 {
72         int fd;
73         uint32_t kernel, initrd, second, pgsz;
74         char buffer[4096];
75         char *p;
76         int r;
77         off_t offset;
78         if (argc < 2)
79                 return 1;
80         fd = open(argv[1], O_RDONLY);
81         if (fd < 0) {
82                 return 2;
83         }
84         r = read(fd, buffer, sizeof(buffer));
85         if (r < 32)
86                 return 3;
87         p = buffer + 8;
88         if (strncmp(buffer, "ANDROID!", 8)) {
89                 return 4;
90         }
91         kernel = *(uint32_t *) p;
92         p += 8;
93         initrd = *(uint32_t *) p;
94         p += 8;
95         second = *(uint32_t *) p;
96         p += 12;
97         pgsz = *(uint32_t *) p;
98         offset = pgsz;
99         if (kernel > 0) {
100                 lseek(fd, offset, SEEK_SET);
101                 dump(fd, kernel, pgsz, "kernel");
102         }
103         offset += ((kernel + pgsz - 1) / pgsz) * pgsz;
104         if (initrd > 0) {
105                 lseek(fd, offset, SEEK_SET);
106                 dump(fd, initrd, pgsz, "initrd");
107         }
108         offset += ((initrd + pgsz - 1) / pgsz) * pgsz;
109         if (second > 0) {
110                 lseek(fd, offset, SEEK_SET);
111                 dump(fd, second, pgsz, "second");
112         }
113         close(fd);
114         return 0;
115 }