1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19#define _GNU_SOURCE
20
21#include <stdio.h>
22#include <stdlib.h>
23#include <stddef.h>
24#include <stdint.h>
25#include <string.h>
26#include <getopt.h>
27#include <unistd.h>
28#include <errno.h>
29#include <sys/stat.h>
30#include <sys/types.h>
31#include <sys/mount.h>
32#include <sys/vfs.h>
33
34#include "linuxioctl.h"
35#include "syslxcom.h"
36#include "syslxfs.h"
37
38const char *program;
39
40int fs_type;
41
42#ifdef DEBUG
43# define dprintf printf
44#else
45# define dprintf(...) ((void)0)
46#endif
47
48#define SECTOR_SHIFT 9
49
50static void die(const char *msg)
51{
52 fputs(msg, stderr);
53 exit(1);
54}
55
56
57
58
59ssize_t xpread(int fd, void *buf, size_t count, off_t offset)
60{
61 char *bufp = (char *)buf;
62 ssize_t rv;
63 ssize_t done = 0;
64
65 while (count) {
66 rv = pread(fd, bufp, count, offset);
67 if (rv == 0) {
68 die("short read");
69 } else if (rv == -1) {
70 if (errno == EINTR) {
71 continue;
72 } else {
73 die(strerror(errno));
74 }
75 } else {
76 bufp += rv;
77 offset += rv;
78 done += rv;
79 count -= rv;
80 }
81 }
82
83 return done;
84}
85
86ssize_t xpwrite(int fd, const void *buf, size_t count, off_t offset)
87{
88 const char *bufp = (const char *)buf;
89 ssize_t rv;
90 ssize_t done = 0;
91
92 while (count) {
93 rv = pwrite(fd, bufp, count, offset);
94 if (rv == 0) {
95 die("short write");
96 } else if (rv == -1) {
97 if (errno == EINTR) {
98 continue;
99 } else {
100 die(strerror(errno));
101 }
102 } else {
103 bufp += rv;
104 offset += rv;
105 done += rv;
106 count -= rv;
107 }
108 }
109
110 return done;
111}
112
113
114
115
116void clear_attributes(int fd)
117{
118 struct stat st;
119
120 if (!fstat(fd, &st)) {
121 switch (fs_type) {
122 case EXT2:
123 {
124 int flags;
125
126 if (!ioctl(fd, FS_IOC_GETFLAGS, &flags)) {
127 flags &= ~FS_IMMUTABLE_FL;
128 ioctl(fd, FS_IOC_SETFLAGS, &flags);
129 }
130 break;
131 }
132 case VFAT:
133 {
134 uint32_t attr = 0x00;
135 ioctl(fd, FAT_IOCTL_SET_ATTRIBUTES, &attr);
136 break;
137 }
138 case NTFS:
139 break;
140 default:
141 break;
142 }
143 fchmod(fd, st.st_mode | S_IWUSR);
144 }
145}
146
147void set_attributes(int fd)
148{
149 struct stat st;
150
151 if (!fstat(fd, &st)) {
152 fchmod(fd, st.st_mode & (S_IRUSR | S_IRGRP | S_IROTH));
153 switch (fs_type) {
154 case EXT2:
155 {
156 int flags;
157
158 if (st.st_uid == 0 && !ioctl(fd, FS_IOC_GETFLAGS, &flags)) {
159 flags |= FS_IMMUTABLE_FL;
160 ioctl(fd, FS_IOC_SETFLAGS, &flags);
161 }
162 break;
163 }
164 case VFAT:
165 {
166 uint32_t attr = 0x07;
167 ioctl(fd, FAT_IOCTL_SET_ATTRIBUTES, &attr);
168 break;
169 }
170 case NTFS:
171 break;
172 default:
173 break;
174 }
175 }
176}
177
178
179static int sectmap_fie(int fd, sector_t *sectors, int nsectors)
180{
181 struct fiemap *fm;
182 struct fiemap_extent *fe;
183 unsigned int i, nsec;
184 sector_t sec, *secp, *esec;
185 struct stat st;
186 uint64_t maplen;
187
188 if (fstat(fd, &st))
189 return -1;
190
191 fm = alloca(sizeof(struct fiemap)
192 + nsectors * sizeof(struct fiemap_extent));
193
194 memset(fm, 0, sizeof *fm);
195
196 maplen = (uint64_t)nsectors << SECTOR_SHIFT;
197 if (maplen > (uint64_t)st.st_size)
198 maplen = st.st_size;
199
200 fm->fm_start = 0;
201 fm->fm_length = maplen;
202 fm->fm_flags = FIEMAP_FLAG_SYNC;
203 fm->fm_extent_count = nsectors;
204
205 if (ioctl(fd, FS_IOC_FIEMAP, fm))
206 return -1;
207
208 memset(sectors, 0, nsectors * sizeof *sectors);
209 esec = sectors + nsectors;
210
211 fe = fm->fm_extents;
212
213 if (fm->fm_mapped_extents < 1 ||
214 !(fe[fm->fm_mapped_extents-1].fe_flags & FIEMAP_EXTENT_LAST))
215 return -1;
216
217 for (i = 0; i < fm->fm_mapped_extents; i++) {
218 if (fe->fe_flags & FIEMAP_EXTENT_LAST) {
219
220 fe->fe_length = (fe->fe_length + SECTOR_SIZE - 1)
221 & ~(SECTOR_SIZE - 1);
222 }
223
224 if ((fe->fe_logical | fe->fe_physical| fe->fe_length) &
225 (SECTOR_SIZE - 1))
226 return -1;
227
228 if (fe->fe_flags & (FIEMAP_EXTENT_UNKNOWN|
229 FIEMAP_EXTENT_DELALLOC|
230 FIEMAP_EXTENT_ENCODED|
231 FIEMAP_EXTENT_DATA_ENCRYPTED|
232 FIEMAP_EXTENT_UNWRITTEN))
233 return -1;
234
235 secp = sectors + (fe->fe_logical >> SECTOR_SHIFT);
236 sec = fe->fe_physical >> SECTOR_SHIFT;
237 nsec = fe->fe_length >> SECTOR_SHIFT;
238
239 while (nsec--) {
240 if (secp >= esec)
241 break;
242 *secp++ = sec++;
243 }
244
245 fe++;
246 }
247
248 return 0;
249}
250
251
252static int sectmap_fib(int fd, sector_t *sectors, int nsectors)
253{
254 unsigned int blk, nblk;
255 unsigned int i;
256 unsigned int blksize;
257 sector_t sec;
258
259
260 if (ioctl(fd, FIGETBSZ, &blksize))
261 return -1;
262
263
264 blksize >>= SECTOR_SHIFT;
265
266 nblk = 0;
267 while (nsectors) {
268 blk = nblk++;
269 if (ioctl(fd, FIBMAP, &blk))
270 return -1;
271
272 sec = (sector_t)blk * blksize;
273 for (i = 0; i < blksize; i++) {
274 *sectors++ = sec++;
275 if (! --nsectors)
276 break;
277 }
278 }
279
280 return 0;
281}
282
283
284
285
286int sectmap(int fd, sector_t *sectors, int nsectors)
287{
288 if (!sectmap_fie(fd, sectors, nsectors))
289 return 0;
290
291 return sectmap_fib(fd, sectors, nsectors);
292}
293
294
295
296
297
298
299int syslinux_already_installed(int dev_fd)
300{
301 char buffer[8];
302
303 xpread(dev_fd, buffer, 8, 3);
304 return !memcmp(buffer, "SYSLINUX", 8) || !memcmp(buffer, "EXTLINUX", 8);
305}
306