1 /* ----------------------------------------------------------------------- *
3 * Copyright 2010 Intel Corp. - All Rights Reserved
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, Inc., 53 Temple Place Ste 330,
8 * Boston MA 02111-1307, USA; either version 2 of the License, or
9 * (at your option) any later version; incorporated herein by reference.
11 * ----------------------------------------------------------------------- */
16 * common functions for extlinux & syslinux installer
30 #include <sys/types.h>
31 #include <sys/mount.h>
34 #include "linuxioctl.h"
43 # define dprintf printf
45 # define dprintf(...) ((void)0)
48 #define SECTOR_SHIFT 9
50 static void die(const char *msg
)
57 * read/write wrapper functions
59 ssize_t
xpread(int fd
, void *buf
, size_t count
, off_t offset
)
61 char *bufp
= (char *)buf
;
66 rv
= pread(fd
, bufp
, count
, offset
);
69 } else if (rv
== -1) {
86 ssize_t
xpwrite(int fd
, const void *buf
, size_t count
, off_t offset
)
88 const char *bufp
= (const char *)buf
;
93 rv
= pwrite(fd
, bufp
, count
, offset
);
96 } else if (rv
== -1) {
100 die(strerror(errno
));
114 * Set and clear file attributes
116 void clear_attributes(int fd
)
120 if (!fstat(fd
, &st
)) {
126 if (!ioctl(fd
, FS_IOC_GETFLAGS
, &flags
)) {
127 flags
&= ~FS_IMMUTABLE_FL
;
128 ioctl(fd
, FS_IOC_SETFLAGS
, &flags
);
134 uint32_t attr
= 0x00; /* Clear all attributes */
135 ioctl(fd
, FAT_IOCTL_SET_ATTRIBUTES
, &attr
);
143 fchmod(fd
, st
.st_mode
| S_IWUSR
);
147 void set_attributes(int fd
)
151 if (!fstat(fd
, &st
)) {
152 fchmod(fd
, st
.st_mode
& (S_IRUSR
| S_IRGRP
| S_IROTH
));
158 if (st
.st_uid
== 0 && !ioctl(fd
, FS_IOC_GETFLAGS
, &flags
)) {
159 flags
|= FS_IMMUTABLE_FL
;
160 ioctl(fd
, FS_IOC_SETFLAGS
, &flags
);
166 uint32_t attr
= 0x07; /* Hidden+System+Readonly */
167 ioctl(fd
, FAT_IOCTL_SET_ATTRIBUTES
, &attr
);
178 /* New FIEMAP based mapping */
179 static int sectmap_fie(int fd
, sector_t
*sectors
, int nsectors
)
182 struct fiemap_extent
*fe
;
183 unsigned int i
, nsec
;
184 sector_t sec
, *secp
, *esec
;
191 fm
= alloca(sizeof(struct fiemap
)
192 + nsectors
* sizeof(struct fiemap_extent
));
194 memset(fm
, 0, sizeof *fm
);
196 maplen
= (uint64_t)nsectors
<< SECTOR_SHIFT
;
197 if (maplen
> (uint64_t)st
.st_size
)
201 fm
->fm_length
= maplen
;
202 fm
->fm_flags
= FIEMAP_FLAG_SYNC
;
203 fm
->fm_extent_count
= nsectors
;
205 if (ioctl(fd
, FS_IOC_FIEMAP
, fm
))
208 memset(sectors
, 0, nsectors
* sizeof *sectors
);
209 esec
= sectors
+ nsectors
;
213 if (fm
->fm_mapped_extents
< 1 ||
214 !(fe
[fm
->fm_mapped_extents
-1].fe_flags
& FIEMAP_EXTENT_LAST
))
217 for (i
= 0; i
< fm
->fm_mapped_extents
; i
++) {
218 if (fe
->fe_flags
& FIEMAP_EXTENT_LAST
) {
219 /* If this is the *final* extent, pad the length */
220 fe
->fe_length
= (fe
->fe_length
+ SECTOR_SIZE
- 1)
221 & ~(SECTOR_SIZE
- 1);
224 if ((fe
->fe_logical
| fe
->fe_physical
| fe
->fe_length
) &
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
))
235 secp
= sectors
+ (fe
->fe_logical
>> SECTOR_SHIFT
);
236 sec
= fe
->fe_physical
>> SECTOR_SHIFT
;
237 nsec
= fe
->fe_length
>> SECTOR_SHIFT
;
251 /* Legacy FIBMAP based mapping */
252 static int sectmap_fib(int fd
, sector_t
*sectors
, int nsectors
)
254 unsigned int blk
, nblk
;
256 unsigned int blksize
;
260 if (ioctl(fd
, FIGETBSZ
, &blksize
))
263 /* Number of sectors per block */
264 blksize
>>= SECTOR_SHIFT
;
269 if (ioctl(fd
, FIBMAP
, &blk
))
272 sec
= (sector_t
)blk
* blksize
;
273 for (i
= 0; i
< blksize
; i
++) {
286 int sectmap(int fd
, sector_t
*sectors
, int nsectors
)
288 if (!sectmap_fie(fd
, sectors
, nsectors
))
291 return sectmap_fib(fd
, sectors
, nsectors
);
295 * SYSLINUX installs the string 'SYSLINUX' at offset 3 in the boot
296 * sector; this is consistent with FAT filesystems. Earlier versions
297 * would install the string "EXTLINUX" instead, handle both.
299 int syslinux_already_installed(int dev_fd
)
303 xpread(dev_fd
, buffer
, 8, 3);
304 return !memcmp(buffer
, "SYSLINUX", 8) || !memcmp(buffer
, "EXTLINUX", 8);