1 /*
2 * Copyright (C) 2023 Rockchip Electronics Co., Ltd.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #define _GNU_SOURCE
18
19 #include <dirent.h>
20 #include <libgen.h>
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <unistd.h>
25 #include <sys/stat.h>
26 #include <sys/types.h>
27 #include <sys/wait.h>
28 #include <sys/mount.h>
29 #include <errno.h>
30 #include "mtdutils.h"
31 #include "rk29.h"
32 #include "common.h"
33
run(const char * filename,char * const argv[])34 int run(const char *filename, char *const argv[])
35 {
36 struct stat s;
37 int status;
38 pid_t pid;
39
40 if (stat(filename, &s) != 0) {
41 LOGE("cannot find '%s'", filename);
42 return -1;
43 }
44
45 LOGI("executing '%s'\n", filename);
46
47 pid = fork();
48
49 if (pid == 0) {
50 setpgid(0, getpid());
51 /* execute */
52 execv(filename, argv);
53 LOGE("can't run %s (%s)\n", filename, strerror(errno));
54 /* exit */
55 _exit(0);
56 }
57
58 if (pid < 0) {
59 LOGE("failed to fork and start '%s'\n", filename);
60 return -1;
61 }
62
63 if (-1 == waitpid(pid, &status, WCONTINUED | WUNTRACED)) {
64 LOGE("wait for child error\n");
65 return -1;
66 }
67
68 if (WIFEXITED(status)) {
69 LOGI("executed '%s' done\n", filename);
70 }
71
72 LOGI("executed '%s' return %d\n", filename, WEXITSTATUS(status));
73 return 0;
74 }
75
rk_check_and_resizefs(const char * filename)76 int rk_check_and_resizefs(const char *filename)
77 {
78 int result;
79
80 const char *const e2fsck_argv[] = { "/sbin/e2fsck", "-fy", filename, NULL };
81 const char *const resizefs_argv[] = { "/sbin/resize2fs", filename, NULL };
82
83 result = run(e2fsck_argv[0], (char **) e2fsck_argv);
84 if (result) {
85 LOGI("e2fsck check '%s' failed!\n", filename);
86 return result;
87 }
88
89 result = run(resizefs_argv[0], (char **) resizefs_argv);
90 if (result) {
91 LOGI("resizefs '%s' failed!\n", filename);
92 }
93
94 return result;
95 }
96
rk_check_and_resizefs_f2fs(const char * filename)97 int rk_check_and_resizefs_f2fs(const char *filename)
98 {
99 int result;
100
101 const char *const e2fsck_argv[] = { "fsck_f2fs", filename, NULL };
102 const char *const resizefs_argv[] = { "resize.f2fs", filename, NULL };
103
104 result = run(e2fsck_argv[0], (char **) e2fsck_argv);
105 if (result) {
106 LOGI("fsck_f2fs check '%s' failed!\n", filename);
107 return result;
108 }
109
110 result = run(resizefs_argv[0], (char **) resizefs_argv);
111 if (result) {
112 LOGI("resize.f2fs '%s' failed!\n", filename);
113 }
114
115 return result;
116 }
117
make_extfs(const char * path,const char * label,const char * type)118 static int make_extfs(const char *path, const char *label, const char *type)
119 {
120 const char *const mke2fs[] = {
121 "/sbin/mke2fs", "-t", type, "-q", path, NULL,
122 };
123
124 // max-mount-counts(0) + time-dependent checking(0) + fslabel
125 const char *const tune2fs[] = {
126 "/sbin/tune2fs", "-c", "0", "-i", "0", "-L", label, path, NULL,
127 };
128 int result;
129
130 LOGI("format '%s' to %s filesystem\n", path, type);
131 result = run(mke2fs[0], (char **) mke2fs);
132 if (result) {
133 LOGI("failed!\n");
134 return result;
135 }
136
137 result = run(tune2fs[0], (char **) tune2fs);
138 if (result) {
139 LOGI("failed!\n");
140 return result;
141 }
142
143 return result;
144 }
145
make_ext2(const char * path,const char * label)146 int make_ext2(const char *path, const char *label)
147 {
148 return make_extfs(path, label, "ext2");
149 }
150
make_ext4(const char * path,const char * label)151 int make_ext4(const char *path, const char *label)
152 {
153 return make_extfs(path, label, "ext4");
154 }
155
make_vfat(const char * path,const char * label)156 int make_vfat(const char *path, const char *label)
157 {
158 // fat32
159 const char *const mkdosfs[] = {
160 "/sbin/mkdosfs", "-F", "32", "-n", label, path, NULL,
161 };
162
163 LOGI("format '%s' to vfat filesystem\n", path);
164 return run(mkdosfs[0], (char **) mkdosfs);
165 }
166
make_ntfs(const char * path,const char * label)167 int make_ntfs(const char *path, const char *label)
168 {
169 // compression
170 const char *const mkntfs[] = {
171 "mkntfs", "-F", "C", "Q", "-L", label, path, NULL,
172 };
173
174 LOGI("format '%s' to ntfs filesystem\n", path);
175 return run(mkntfs[0], (char **) mkntfs);
176 }
177
178 #ifndef min
179 #define min(a,b) ((a)<(b)?(a):(b))
180 #endif
181
rk29_fread(void * ptr,size_t size,size_t nmemb,FILE * stream)182 size_t rk29_fread(void *ptr, size_t size, size_t nmemb, FILE *stream)
183 {
184 char buf[READ_SIZE];
185 int fd;
186 long begin, end;
187 off_t offset;
188 ssize_t sz;
189 size_t count = 0, total;
190 char *p = ptr;
191
192 if (!ptr)
193 return 0;
194 if (!size || !nmemb)
195 return 0;
196 if (!stream)
197 return 0;
198 fd = fileno(stream);
199 if (fd < 0)
200 return 0;
201
202 begin = ftell(stream);
203 if (begin < 0)
204 begin = 0;
205
206 total = size * nmemb;
207 if (!total)
208 return 0;
209
210 end = begin + total;
211 offset = begin & ~READ_MASK;
212
213 if (begin & READ_MASK) {
214 sz = pread(fd, buf, READ_SIZE, offset);
215 if (sz < READ_SIZE)
216 goto out;
217 count = min(end, offset + READ_SIZE) - begin;
218 memcpy(p, buf + (begin & READ_MASK), count);
219 p += count;
220 offset += READ_SIZE;
221 }
222
223 for (; offset < (end & ~READ_MASK); offset += READ_SIZE) {
224 sz = pread(fd, buf, READ_SIZE, offset);
225 if (sz < READ_SIZE)
226 goto out;
227 count += READ_SIZE;
228 memcpy(p, buf, READ_SIZE);
229 p += READ_SIZE;
230 }
231
232 if (count < total && (end & READ_MASK)) {
233 offset = end & ~READ_MASK;
234 sz = pread(fd, buf, READ_SIZE, offset);
235 if (sz < READ_SIZE)
236 goto out;
237 memcpy(p, buf, end - offset);
238 count += end - offset;
239 }
240 out:
241 count /= size;
242 fseek(stream, begin + count * size, SEEK_SET);
243 return count;
244 }
245
rk29_fwrite(const void * ptr,size_t size,size_t nmemb,FILE * stream)246 size_t rk29_fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream)
247 {
248 char buf[WRITE_SIZE];
249 int fd;
250 long begin, end;
251 off_t offset;
252 ssize_t sz;
253 size_t count = 0, total;
254 char *p = (char *)ptr;
255
256 if (!ptr)
257 return 0;
258 if (!size || !nmemb)
259 return 0;
260 if (!stream)
261 return 0;
262 fd = fileno(stream);
263 if (fd < 0)
264 return 0;
265
266 begin = ftell(stream);
267 if (begin < 0)
268 begin = 0;
269
270 total = size * nmemb;
271 if (!total)
272 return 0;
273
274 end = begin + total;
275 offset = begin & ~WRITE_MASK;
276
277 if (begin & WRITE_MASK) {
278 sz = pread(fd, buf, WRITE_SIZE, offset);
279 if (sz < WRITE_SIZE)
280 goto out;
281 count = min(end, offset + WRITE_SIZE) - begin;
282 memcpy(buf + (begin & WRITE_MASK), p, count);
283 sz = pwrite(fd, buf, WRITE_SIZE, offset);
284 if (sz < WRITE_SIZE)
285 goto out;
286 p += count;
287 offset += WRITE_SIZE;
288 }
289
290 for (; offset < (end & ~WRITE_MASK); offset += WRITE_SIZE) {
291 sz = pwrite(fd, p, WRITE_SIZE, offset);
292 if (sz < WRITE_SIZE)
293 goto out;
294 count += WRITE_SIZE;
295 p += WRITE_SIZE;
296 }
297
298 if (count < total && (end & WRITE_MASK)) {
299 offset = end & ~WRITE_MASK;
300 sz = pread(fd, buf, WRITE_SIZE, offset);
301 if (sz < WRITE_SIZE)
302 goto out;
303 memcpy(buf, p, end - offset);
304 sz = pwrite(fd, buf, WRITE_SIZE, offset);
305 if (sz < WRITE_SIZE)
306 goto out;
307 count += end - offset;
308 }
309 out:
310 count /= size;
311 fseek(stream, begin + count * size, SEEK_SET);
312 return count;
313 }
314
315