source: packages/utils/calvaria/files/src/calvaria.c @ 25235

Last change on this file since 25235 was 25235, checked in by mb, 5 years ago

Add calvaria. Tool to access Maemo CAL partition.

File size: 9.8 KB
Line 
1/*
2 * Calvaria - Maemo CAL partition variable access tool.
3 *
4 * Copyright (c) 2011 Michael Buesch <mb@bu3sch.de>
5 *
6 * Licensed under the GNU General Public License
7 * version 2 or (at your option) any later version.
8 */
9
10#include <stdlib.h>
11#include <stdio.h>
12#include <string.h>
13#include <getopt.h>
14#include <unistd.h>
15#include <fcntl.h>
16#include <errno.h>
17#include <stdint.h>
18#include <sys/mman.h>
19
20
21#define _packed         __attribute__((__packed__))
22
23typedef uint16_t le16_t;
24typedef uint32_t le32_t;
25
26struct header {
27        char magic[4];          /* Magic sequence */
28        uint8_t type;           /* Type number */
29        uint8_t index;          /* Index number */
30        le16_t flags;           /* Flags */
31        char name[16];          /* Human readable section name */
32        le32_t length;          /* Payload length */
33        le32_t datasum;         /* Data CRC32 checksum */
34        le32_t hdrsum;          /* Header CRC32 checksum */
35} _packed;
36
37#define HDR_MAGIC       "ConF"
38
39
40static char toAscii(char c)
41{
42        if (c >= 32 && c <= 126)
43                return c;
44        return '.';
45}
46
47static void dump(FILE *outstream, const char *buf, size_t size)
48{
49        size_t i, ascii_cnt = 0;
50        char ascii[17] = { 0, };
51
52        for (i = 0; i < size; i++) {
53                if (i % 16 == 0) {
54                        if (i != 0) {
55                                fprintf(outstream, "  |%s|\n", ascii);
56                                ascii[0] = 0;
57                                ascii_cnt = 0;
58                        }
59                        fprintf(outstream, "[%04X]: ", (unsigned int)i);
60                }
61                fprintf(outstream, " %02X", buf[i]);
62                ascii[ascii_cnt] = toAscii(buf[i]);
63                ascii[ascii_cnt + 1] = 0;
64                ascii_cnt++;
65        }
66        if (ascii[0]) {
67                if (size % 16) {
68                        for (i = 0; i < 16 - (size % 16); i++)
69                                fprintf(outstream, "   ");
70                }
71                fprintf(outstream, "  |%s|\n", ascii);
72        }
73        fprintf(outstream, "\n");
74}
75
76static uint32_t crc32(uint32_t crc, const void *_data, size_t size)
77{
78        const uint8_t *data = _data;
79        uint8_t value;
80        unsigned int bit;
81        size_t i;
82        const uint32_t poly = 0xEDB88320;
83
84        for (i = 0; i < size; i++) {
85                value = data[i];
86                for (bit = 8; bit; bit--) {
87                        if ((crc & 1) != (value & 1))
88                                crc = (crc >> 1) ^ poly;
89                        else
90                                crc >>= 1;
91                        value >>= 1;
92                }
93        }
94
95        return crc;
96}
97
98static inline uint16_t le16_to_cpu(le16_t x)
99{
100        uint8_t *bytes = (uint8_t *)&x;
101        uint16_t ret;
102
103        ret = bytes[0];
104        ret |= (uint16_t)(bytes[1]) << 8;
105
106        return ret;
107}
108
109static inline uint32_t le32_to_cpu(le32_t x)
110{
111        uint8_t *bytes = (uint8_t *)&x;
112        uint32_t ret;
113
114        ret = bytes[0];
115        ret |= (uint32_t)(bytes[1]) << 8;
116        ret |= (uint32_t)(bytes[2]) << 16;
117        ret |= (uint32_t)(bytes[3]) << 24;
118
119        return ret;
120}
121
122static int is_header(void *data, size_t size)
123{
124        struct header *hdr = data;
125
126        if (size < sizeof(struct header))
127                return 0;
128        if (memcmp(hdr->magic, HDR_MAGIC, sizeof(hdr->magic)) != 0)
129                return 0;
130        return 1;
131}
132
133static int dump_section(const struct header *hdr,
134                        const void *payload, size_t payload_len,
135                        int dump_payload,
136                        FILE *outstream)
137{
138        char name[sizeof(hdr->name) + 1] = { 0, };
139        int hdrsum_ok, datasum_ok;
140
141        memcpy(name, hdr->name, sizeof(hdr->name));
142        hdrsum_ok = (crc32(0, hdr, sizeof(*hdr) - 4) == le32_to_cpu(hdr->hdrsum));
143        datasum_ok = (crc32(0, payload, payload_len) == le32_to_cpu(hdr->datasum));
144
145        fprintf(outstream, "Section:       %s\n", name);
146        fprintf(outstream, "Type:          %u (0x%X)\n", hdr->type, hdr->type);
147        fprintf(outstream, "Index:         %u (0x%X)\n", hdr->index, hdr->index);
148        fprintf(outstream, "Flags:         0x%04X\n", le16_to_cpu(hdr->flags));
149        fprintf(outstream, "Length:        %u (0x%X)\n",
150                le32_to_cpu(hdr->length), le32_to_cpu(hdr->length));
151        fprintf(outstream, "Data CRC32:    0x%08X (%s)\n", le32_to_cpu(hdr->datasum),
152                datasum_ok ? "Ok" : "MISMATCH");
153        fprintf(outstream, "Header CRC32:  0x%08X (%s)\n", le32_to_cpu(hdr->hdrsum),
154                hdrsum_ok ? "Ok" : "MISMATCH");
155        if (dump_payload)
156                dump(outstream, payload, payload_len);
157        fprintf(outstream, "\n");
158
159        return 0;
160}
161
162static void * map_file(const char *filepath, int readonly,
163                       uint64_t *filelen)
164{
165        int fd;
166        off_t len;
167        void *data;
168
169        fd = open(filepath, readonly ? O_RDONLY : O_RDWR);
170        if (fd < 0) {
171                fprintf(stderr, "Failed to open file %s: %s\n",
172                        filepath, strerror(errno));
173                return NULL;
174        }
175        len = lseek(fd, 0, SEEK_END);
176        if (len < 0 || lseek(fd, 0, SEEK_SET)) {
177                fprintf(stderr, "Failed to calculate file length of %s: %s\n",
178                        filepath, strerror(errno));
179                close(fd);
180                return NULL;
181        }
182
183        data = mmap(NULL, len,
184                    readonly ? PROT_READ : (PROT_READ | PROT_WRITE),
185                    readonly ? MAP_PRIVATE : 0,
186                    fd, 0);
187        close(fd);
188        if (data == MAP_FAILED) {
189                fprintf(stderr, "Failed to MMAP file %s: %s\n",
190                        filepath, strerror(errno));
191                return NULL;
192        }
193        madvise(data, len, MADV_SEQUENTIAL);
194
195        *filelen = len;
196
197        return data;
198}
199
200static void unmap_file(void *mapping, uint64_t len)
201{
202        munmap(mapping, len);
203}
204
205static int64_t find_section(void *start, uint64_t count,
206                            int want_index, const char *want_name)
207{
208        uint64_t offset = 0;
209        uint8_t *data = start;
210        struct header *hdr;
211        char sectname[sizeof(hdr->name) + 1] = { 0, };
212        uint32_t payload_len;
213
214        while (1) {
215                /* Find header start */
216                if (count < sizeof(struct header))
217                        break;
218                if (!is_header(data + offset, count)) {
219                        count--;
220                        offset++;
221                        continue;
222                }
223                hdr = (struct header *)(data + offset);
224                payload_len = le32_to_cpu(hdr->length);
225                if (count - sizeof(struct header) < payload_len) {
226                        fprintf(stderr, "Premature EOF\n");
227                        return -1;
228                }
229                memcpy(sectname, hdr->name, sizeof(hdr->name));
230
231                if (want_index >= 0 && want_index != hdr->index)
232                        goto next;
233                if (want_name && strcmp(sectname, want_name) != 0)
234                        goto next;
235
236                /* Found it */
237                return offset;
238
239next:
240                count -= sizeof(struct header) + payload_len;
241                offset += sizeof(struct header) + payload_len;
242        }
243
244        return -1;
245}
246
247static int dump_image(const char *filepath,
248                      int want_section_index, const char *want_section_name,
249                      int want_headers_only,
250                      FILE *outstream)
251{
252        int err, ret = 0;
253        uint64_t filelen;
254        uint64_t count, offset;
255        int64_t find_offset;
256        uint8_t *data, *section;
257        struct header *hdr;
258        uint32_t payload_len;
259
260        data = map_file(filepath, 1, &filelen);
261        if (!data)
262                return -EIO;
263
264        count = filelen;
265        offset = 0;
266        while (1) {
267                find_offset = find_section(data + offset, count,
268                                           want_section_index, want_section_name);
269                if (find_offset < 0)
270                        break;
271                offset += find_offset;
272                count -= find_offset;
273
274                section = data + offset;
275                hdr = (struct header *)section;
276                payload_len = le32_to_cpu(hdr->length);
277
278                err = dump_section(hdr, section + sizeof(struct header),
279                                   payload_len,
280                                   !want_headers_only,
281                                   outstream);
282                if (err) {
283                        ret = err;
284                        goto out;
285                }
286
287                count -= sizeof(struct header) + payload_len;
288                offset += sizeof(struct header) + payload_len;
289        }
290out:
291        unmap_file(data, filelen);
292
293        return ret;
294}
295
296static int write_payload(const char *filepath,
297                         int want_section_index, const char *want_section_name,
298                         FILE *outstream)
299{
300        int64_t find_offset;
301        uint64_t filelen;
302        uint8_t *data;
303        struct header *hdr;
304
305        data = map_file(filepath, 1, &filelen);
306        if (!data)
307                return -EIO;
308
309        find_offset = find_section(data, filelen,
310                                   want_section_index, want_section_name);
311        if (find_offset < 0) {
312                fprintf(stderr, "Section %s, index %d not found\n",
313                        want_section_name, want_section_index);
314                unmap_file(data, filelen);
315                return -ESRCH;
316        }
317
318        hdr = (struct header *)(data + find_offset);
319        if (fwrite(data + find_offset + sizeof(struct header),
320                   le32_to_cpu(hdr->length), 1, outstream) != 1) {
321                fprintf(stderr, "Could not write output data\n");
322                unmap_file(data, filelen);
323                return -EIO;
324        }
325
326        unmap_file(data, filelen);
327
328        return 0;
329}
330
331static void usage(FILE *fd)
332{
333        fprintf(fd, "Calvaria - Maemo CAL partition variable access tool\n");
334        fprintf(fd, "\n");
335        fprintf(fd, "Usage: calvaria [OPTIONS] FILE\n");
336        fprintf(fd, "\n");
337        fprintf(fd, "Actions:\n");
338        fprintf(fd, "  -d|--dump            Dump the contents of the image\n");
339        fprintf(fd, "  -H|--headers         Dump the headers of the image, only\n");
340        fprintf(fd, "  -p|--payload         Write the binary payload to stdout.\n");
341        fprintf(fd, "                       Requires -i and -n to be set, too\n");
342        fprintf(fd, "\n");
343        fprintf(fd, "Options:\n");
344        fprintf(fd, "  -i|--index NUMBER    Use this section index number\n");
345        fprintf(fd, "  -n|--name STRING     Use this section name\n");
346        fprintf(fd, "\n");
347        fprintf(fd, "  -h|--help            Print this help text\n");
348}
349
350enum action {
351        ACTION_NONE,
352        ACTION_DUMP,
353        ACTION_DUMPHDRS,
354        ACTION_GETPAYLOAD,
355};
356
357int main(int argc, char **argv)
358{
359        int err, c, idx = 0;
360        const char *filepath;
361        enum action action = ACTION_NONE;
362        int opt_index = -1;
363        const char *opt_name = NULL;
364
365        static struct option long_options[] = {
366                { "dump", no_argument, 0, 'd', },
367                { "headers", no_argument, 0, 'H', },
368                { "payload", no_argument, 0, 'p', },
369                { "index", required_argument, 0, 'i', },
370                { "name", required_argument, 0, 'n', },
371                { "help", no_argument, 0, 'h', },
372                { },
373        };
374
375        while (1) {
376                c = getopt_long(argc, argv, "dHphi:n:",
377                                long_options, &idx);
378                if (c == -1)
379                        break;
380                switch (c) {
381                case 'h':
382                        usage(stdout);
383                        return 0;
384                case 'd':
385                        action = ACTION_DUMP;
386                        break;
387                case 'H':
388                        action = ACTION_DUMPHDRS;
389                        break;
390                case 'p':
391                        action = ACTION_GETPAYLOAD;
392                        break;
393                case 'i':
394                        if (sscanf(optarg, "%d", &opt_index) != 1 || opt_index < 0) {
395                                fprintf(stderr, "-i|--index is not a positive integer\n");
396                                return 1;
397                        }
398                        break;
399                case 'n':
400                        opt_name = optarg;
401                        break;
402                default:
403                        return 1;
404                }
405        }
406        argc -= optind;
407        argv += optind;
408        if (action == ACTION_NONE) {
409                fprintf(stderr, "No action specified.\n");
410                return 1;
411        }
412        if (action == ACTION_GETPAYLOAD) {
413                if (opt_index < 0 || !opt_name) {
414                        fprintf(stderr, "Required options -i|--index or -n|--name "
415                                "not specified for action -p|--payload\n");
416                        return 1;
417                }
418        }
419        if (argc != 1) {
420                usage(stderr);
421                return 1;
422        }
423        filepath = argv[0];
424
425        switch (action) {
426        case ACTION_NONE:
427                break;
428        case ACTION_DUMP:
429        case ACTION_DUMPHDRS:
430                err = dump_image(filepath, opt_index, opt_name,
431                                 (action == ACTION_DUMPHDRS),
432                                 stdout);
433                if (err)
434                        return 1;
435                break;
436        case ACTION_GETPAYLOAD:
437                err = write_payload(filepath, opt_index, opt_name, stdout);
438                if (err)
439                        return 1;
440                break;
441        }
442
443        return 0;
444}
Note: See TracBrowser for help on using the repository browser.