2 * Calvaria - Maemo CAL partition variable access tool.
4 * Copyright (c) 2011 Michael Buesch <mb@bu3sch.de>
6 * Licensed under the GNU General Public License
7 * version 2 or (at your option) any later version.
21 #define _packed __attribute__((__packed__))
23 typedef uint16_t le16_t
;
24 typedef uint32_t le32_t
;
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 */
37 #define HDR_MAGIC "ConF"
40 static char toAscii(char c
)
42 if (c
>= 32 && c
<= 126)
47 static void dump(FILE *outstream
, const char *buf
, size_t size
)
49 size_t i
, ascii_cnt
= 0;
50 char ascii
[17] = { 0, };
52 for (i
= 0; i
< size
; i
++) {
55 fprintf(outstream
, " |%s|\n", ascii
);
59 fprintf(outstream
, "[%04X]: ", (unsigned int)i
);
61 fprintf(outstream
, " %02X", buf
[i
]);
62 ascii
[ascii_cnt
] = toAscii(buf
[i
]);
63 ascii
[ascii_cnt
+ 1] = 0;
68 for (i
= 0; i
< 16 - (size
% 16); i
++)
69 fprintf(outstream
, " ");
71 fprintf(outstream
, " |%s|\n", ascii
);
73 fprintf(outstream
, "\n");
76 static uint32_t crc32(uint32_t crc
, const void *_data
, size_t size
)
78 const uint8_t *data
= _data
;
82 const uint32_t poly
= 0xEDB88320;
84 for (i
= 0; i
< size
; i
++) {
86 for (bit
= 8; bit
; bit
--) {
87 if ((crc
& 1) != (value
& 1))
88 crc
= (crc
>> 1) ^ poly
;
98 static inline uint16_t le16_to_cpu(le16_t x
)
100 uint8_t *bytes
= (uint8_t *)&x
;
104 ret
|= (uint16_t)(bytes
[1]) << 8;
109 static inline uint32_t le32_to_cpu(le32_t x
)
111 uint8_t *bytes
= (uint8_t *)&x
;
115 ret
|= (uint32_t)(bytes
[1]) << 8;
116 ret
|= (uint32_t)(bytes
[2]) << 16;
117 ret
|= (uint32_t)(bytes
[3]) << 24;
122 static int is_header(void *data
, size_t size
)
124 struct header
*hdr
= data
;
126 if (size
< sizeof(struct header
))
128 if (memcmp(hdr
->magic
, HDR_MAGIC
, sizeof(hdr
->magic
)) != 0)
133 static int dump_section(const struct header
*hdr
,
134 const void *payload
, size_t payload_len
,
138 char name
[sizeof(hdr
->name
) + 1] = { 0, };
139 int hdrsum_ok
, datasum_ok
;
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
));
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");
156 dump(outstream
, payload
, payload_len
);
157 fprintf(outstream
, "\n");
162 static void * map_file(const char *filepath
, int readonly
,
169 fd
= open(filepath
, readonly
? O_RDONLY
: O_RDWR
);
171 fprintf(stderr
, "Failed to open file %s: %s\n",
172 filepath
, strerror(errno
));
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
));
183 data
= mmap(NULL
, len
,
184 readonly
? PROT_READ
: (PROT_READ
| PROT_WRITE
),
185 readonly
? MAP_PRIVATE
: 0,
188 if (data
== MAP_FAILED
) {
189 fprintf(stderr
, "Failed to MMAP file %s: %s\n",
190 filepath
, strerror(errno
));
193 madvise(data
, len
, MADV_SEQUENTIAL
);
200 static void unmap_file(void *mapping
, uint64_t len
)
202 munmap(mapping
, len
);
205 static int64_t find_section(void *start
, uint64_t count
,
206 int want_index
, const char *want_name
)
209 uint8_t *data
= start
;
211 char sectname
[sizeof(hdr
->name
) + 1] = { 0, };
212 uint32_t payload_len
;
215 /* Find header start */
216 if (count
< sizeof(struct header
))
218 if (!is_header(data
+ offset
, count
)) {
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");
229 memcpy(sectname
, hdr
->name
, sizeof(hdr
->name
));
231 if (want_index
>= 0 && want_index
!= hdr
->index
)
233 if (want_name
&& strcmp(sectname
, want_name
) != 0)
240 count
-= sizeof(struct header
) + payload_len
;
241 offset
+= sizeof(struct header
) + payload_len
;
247 static int dump_image(const char *filepath
,
248 int want_section_index
, const char *want_section_name
,
249 int want_headers_only
,
254 uint64_t count
, offset
;
256 uint8_t *data
, *section
;
258 uint32_t payload_len
;
260 data
= map_file(filepath
, 1, &filelen
);
267 find_offset
= find_section(data
+ offset
, count
,
268 want_section_index
, want_section_name
);
271 offset
+= find_offset
;
272 count
-= find_offset
;
274 section
= data
+ offset
;
275 hdr
= (struct header
*)section
;
276 payload_len
= le32_to_cpu(hdr
->length
);
278 err
= dump_section(hdr
, section
+ sizeof(struct header
),
287 count
-= sizeof(struct header
) + payload_len
;
288 offset
+= sizeof(struct header
) + payload_len
;
291 unmap_file(data
, filelen
);
296 static int write_payload(const char *filepath
,
297 int want_section_index
, const char *want_section_name
,
305 data
= map_file(filepath
, 1, &filelen
);
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
);
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
);
326 unmap_file(data
, filelen
);
331 static void usage(FILE *fd
)
333 fprintf(fd
, "Calvaria - Maemo CAL partition variable access tool\n");
335 fprintf(fd
, "Usage: calvaria [OPTIONS] FILE\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");
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");
347 fprintf(fd
, " -h|--help Print this help text\n");
357 int main(int argc
, char **argv
)
360 const char *filepath
;
361 enum action action
= ACTION_NONE
;
363 const char *opt_name
= NULL
;
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', },
376 c
= getopt_long(argc
, argv
, "dHphi:n:",
385 action
= ACTION_DUMP
;
388 action
= ACTION_DUMPHDRS
;
391 action
= ACTION_GETPAYLOAD
;
394 if (sscanf(optarg
, "%d", &opt_index
) != 1 || opt_index
< 0) {
395 fprintf(stderr
, "-i|--index is not a positive integer\n");
408 if (action
== ACTION_NONE
) {
409 fprintf(stderr
, "No action specified.\n");
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");
429 case ACTION_DUMPHDRS
:
430 err
= dump_image(filepath
, opt_index
, opt_name
,
431 (action
== ACTION_DUMPHDRS
),
436 case ACTION_GETPAYLOAD
:
437 err
= write_payload(filepath
, opt_index
, opt_name
, stdout
);