firmware-utils: mkdlinkfw: fix error handling
[openwrt/staging/mkresin.git] / tools / firmware-utils / src / mkdlinkfw-lib.c
1 /*
2 * mkdlinkfw
3 *
4 * Copyright (C) 2018 Paweł Dembicki <paweldembicki@gmail.com>
5 *
6 * This tool is based on mktplinkfw.
7 * Copyright (C) 2009 Gabor Juhos <juhosg@openwrt.org>
8 * Copyright (C) 2008,2009 Wang Jian <lark@linux.net.cn>
9 *
10 * This program is free software; you can redistribute it and/or modify it
11 * under the terms of the GNU General Public License as published by the Free
12 * Software Foundation; either version 2 of the License, or (at your option)
13 * any later version.
14 */
15
16 #include <stdio.h>
17 #include <stdlib.h>
18 #include <stdint.h>
19 #include <string.h>
20 #include <unistd.h> /* for unlink() */
21 #include <libgen.h>
22 #include <getopt.h> /* for getopt() */
23 #include <stdarg.h>
24 #include <stdbool.h>
25 #include <endian.h>
26 #include <errno.h>
27 #include <time.h>
28 #include <sys/stat.h>
29 #include <zlib.h> /*for crc32 */
30
31 #include "mkdlinkfw-lib.h"
32
33 extern char *progname;
34
35 uint32_t jboot_timestamp(void)
36 {
37 char *env = getenv("SOURCE_DATE_EPOCH");
38 char *endptr = env;
39 time_t fixed_timestamp = -1;
40 errno = 0;
41
42 if (env && *env) {
43 fixed_timestamp = strtoull(env, &endptr, 10);
44
45 if (errno || (endptr && *endptr != '\0')) {
46 fprintf(stderr, "Invalid SOURCE_DATE_EPOCH");
47 fixed_timestamp = -1;
48 }
49 }
50
51 if (fixed_timestamp == -1)
52 time(&fixed_timestamp);
53
54 return (((uint32_t) fixed_timestamp) - TIMESTAMP_MAGIC) >> 2;
55 }
56
57 uint16_t jboot_checksum(uint16_t start_val, uint16_t *data, int size)
58 {
59 uint32_t counter = start_val;
60 uint16_t *ptr = data;
61
62 while (size > 1) {
63 counter += *ptr;
64 ++ptr;
65 while (counter >> 16)
66 counter = (uint16_t) counter + (counter >> 16);
67 size -= 2;
68 }
69 if (size > 0) {
70 counter += *(uint8_t *) ptr;
71 counter -= 0xFF;
72 }
73 while (counter >> 16)
74 counter = (uint16_t) counter + (counter >> 16);
75 return counter;
76 }
77
78 int get_file_stat(struct file_info *fdata)
79 {
80 struct stat st;
81 int res;
82
83 if (fdata->file_name == NULL)
84 return 0;
85
86 res = stat(fdata->file_name, &st);
87 if (res) {
88 ERRS("stat failed on %s", fdata->file_name);
89 return res;
90 }
91
92 fdata->file_size = st.st_size;
93 return 0;
94 }
95
96 int read_to_buf(const struct file_info *fdata, char *buf)
97 {
98 FILE *f;
99 int ret = EXIT_FAILURE;
100 size_t read;
101
102 f = fopen(fdata->file_name, "r");
103 if (f == NULL) {
104 ERRS("could not open \"%s\" for reading", fdata->file_name);
105 goto out;
106 }
107
108 read = fread(buf, fdata->file_size, 1, f);
109 if (ferror(f) || read != 1) {
110 ERRS("unable to read from file \"%s\"", fdata->file_name);
111 goto out_close;
112 }
113
114 ret = EXIT_SUCCESS;
115
116 out_close:
117 fclose(f);
118 out:
119 return ret;
120 }
121
122 int write_fw(const char *ofname, const char *data, int len)
123 {
124 FILE *f;
125 int ret = EXIT_FAILURE;
126
127 f = fopen(ofname, "w");
128 if (f == NULL) {
129 ERRS("could not open \"%s\" for writing", ofname);
130 goto out;
131 }
132
133 errno = 0;
134 fwrite(data, len, 1, f);
135 if (errno) {
136 ERRS("unable to write output file");
137 goto out_flush;
138 }
139
140 DBG("firmware file \"%s\" completed", ofname);
141
142 ret = EXIT_SUCCESS;
143
144 out_flush:
145 fflush(f);
146 fclose(f);
147 if (ret != EXIT_SUCCESS)
148 unlink(ofname);
149 out:
150 return ret;
151 }