e5b7bc38c2ebf297ad2ec5ec05605a497950ac0b
[project/fstools.git] / libfstools / common.c
1 // SPDX-License-Identifier: GPL-2.0-or-later
2
3 #include "common.h"
4 #define BUFLEN 128
5
6 int
7 read_uint_from_file(char *dirname, char *filename, unsigned int *i)
8 {
9 FILE *f;
10 char fname[BUFLEN];
11 int ret = -1;
12
13 snprintf(fname, sizeof(fname), "%s/%s", dirname, filename);
14
15 f = fopen(fname, "r");
16 if (!f)
17 return ret;
18
19 if (fscanf(f, "%u", i) == 1)
20 ret = 0;
21
22 fclose(f);
23 return ret;
24 }
25
26 char
27 *read_string_from_file(const char *dirname, const char *filename, char *buf, size_t bufsz)
28 {
29 FILE *f;
30 char fname[BUFLEN];
31 int i;
32
33 snprintf(fname, sizeof(fname), "%s/%s", dirname, filename);
34
35 f = fopen(fname, "r");
36 if (!f)
37 return NULL;
38
39 if (fgets(buf, bufsz, f) == NULL) {
40 fclose(f);
41 return NULL;
42 }
43
44 fclose(f);
45
46 /* make sure the string is \0 terminated */
47 buf[bufsz - 1] = '\0';
48
49 /* remove trailing whitespace */
50 i = strlen(buf) - 1;
51 while (i > 0 && buf[i] <= ' ')
52 buf[i--] = '\0';
53
54 return buf;
55 }
56
57 int block_file_identify(FILE *f, uint64_t offset)
58 {
59 uint32_t magic = 0;
60 size_t n;
61
62 if (fseeko(f, offset, SEEK_SET) < 0)
63 return -1;
64
65 n = fread(&magic, sizeof(magic), 1, f);
66 if (magic == cpu_to_le32(0x88b1f))
67 return FS_TARGZ;
68
69 if (magic == cpu_to_be32(0xdeadc0de))
70 return FS_DEADCODE;
71
72 if (fseeko(f, offset + 0x400, SEEK_SET) < 0)
73 return -1;
74
75 n = fread(&magic, sizeof(magic), 1, f);
76 if (n != 1)
77 return -1;
78
79 if (magic == cpu_to_le32(0xF2F52010))
80 return FS_F2FS;
81
82 magic = 0;
83 if (fseeko(f, offset + 0x438, SEEK_SET) < 0)
84 return -1;
85
86 n = fread(&magic, sizeof(magic), 1, f);
87 if (n != 1)
88 return -1;
89
90 if ((le32_to_cpu(magic) & 0xffff) == 0xef53)
91 return FS_EXT4;
92
93 return FS_NONE;
94 }
95
96 static bool use_f2fs(struct volume *v, uint64_t offset, const char *bdev)
97 {
98 uint64_t size = 0;
99 bool ret = false;
100 int fd;
101
102 fd = open(bdev, O_RDONLY);
103 if (fd < 0)
104 return false;
105
106 if (ioctl(fd, BLKGETSIZE64, &size) == 0)
107 ret = size - offset > F2FS_MINSIZE;
108
109 close(fd);
110
111 return ret;
112 }
113
114 int block_volume_format(struct volume *v, uint64_t offset, const char *bdev)
115 {
116 int ret = 0;
117 char str[128];
118 unsigned int skip_blocks = 0;
119 int fd;
120 __u32 deadc0de;
121 size_t sz;
122
123 switch (volume_identify(v)) {
124 case FS_DEADCODE:
125 /* skip padding */
126 fd = open(v->blk, O_RDONLY);
127 if (fd < 0) {
128 ret = EIO;
129 break;
130 }
131 do {
132 if (lseek(fd, (skip_blocks + 1) * 512, SEEK_SET) == (off_t) -1) {
133 ret = EIO;
134 break;
135 }
136 sz = read(fd, &deadc0de, sizeof(deadc0de));
137 if (sz != sizeof(deadc0de)) {
138 ret = EIO;
139 break;
140 }
141 } while(++skip_blocks <= 512 &&
142 (deadc0de == cpu_to_be32(0xdeadc0de) || deadc0de == 0xffffffff));
143
144 close(fd);
145 if (ret)
146 break;
147
148 /* only try extracting in case gzip header is present */
149 if (deadc0de != cpu_to_le32(0x88b1f))
150 goto do_format;
151
152 /* fall-through */
153 case FS_TARGZ:
154 snprintf(str, sizeof(str),
155 "dd if=%s bs=512 skip=%u 2>/dev/null | gzip -cd > /tmp/sysupgrade.tar 2>/dev/null",
156 v->blk, skip_blocks);
157 ret = system(str);
158 if (ret < 0) {
159 ULOG_ERR("failed extracting config backup from %s\n", v->blk);
160 break;
161 }
162 /* fall-through */
163 case FS_NONE:
164 do_format:
165 ULOG_INFO("overlay filesystem in %s has not been formatted yet\n", v->blk);
166 if (use_f2fs(v, offset, bdev))
167 snprintf(str, sizeof(str), "mkfs.f2fs -q -l rootfs_data %s", v->blk);
168 else
169 snprintf(str, sizeof(str), "mkfs.ext4 -q -L rootfs_data %s", v->blk);
170
171 ret = system(str);
172 break;
173 default:
174 break;
175 }
176
177 return ret;
178 }