hdt: Making dumping code easier to use
[syslinux.git] / libinstaller / syslxcom.c
blobb176f6d78bd47841d500435652ce4eecbf157e38
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 * ----------------------------------------------------------------------- */
14 * syslxcom.c
16 * common functions for extlinux & syslinux installer
19 #define _GNU_SOURCE
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 #include "linuxioctl.h"
34 #include "syslxcom.h"
36 const char *program;
38 int fs_type;
40 #ifdef DEBUG
41 # define dprintf printf
42 #else
43 # define dprintf(...) ((void)0)
44 #endif
46 #define SECTOR_SHIFT 9
48 static void die(const char *msg)
50 fputs(msg, stderr);
51 exit(1);
55 * read/write wrapper functions
57 ssize_t xpread(int fd, void *buf, size_t count, off_t offset)
59 char *bufp = (char *)buf;
60 ssize_t rv;
61 ssize_t done = 0;
63 while (count) {
64 rv = pread(fd, bufp, count, offset);
65 if (rv == 0) {
66 die("short read");
67 } else if (rv == -1) {
68 if (errno == EINTR) {
69 continue;
70 } else {
71 die(strerror(errno));
73 } else {
74 bufp += rv;
75 offset += rv;
76 done += rv;
77 count -= rv;
81 return done;
84 ssize_t xpwrite(int fd, const void *buf, size_t count, off_t offset)
86 const char *bufp = (const char *)buf;
87 ssize_t rv;
88 ssize_t done = 0;
90 while (count) {
91 rv = pwrite(fd, bufp, count, offset);
92 if (rv == 0) {
93 die("short write");
94 } else if (rv == -1) {
95 if (errno == EINTR) {
96 continue;
97 } else {
98 die(strerror(errno));
100 } else {
101 bufp += rv;
102 offset += rv;
103 done += rv;
104 count -= rv;
108 return done;
112 * Set and clear file attributes
114 void clear_attributes(int fd)
116 struct stat st;
118 if (!fstat(fd, &st)) {
119 switch (fs_type) {
120 case EXT2:
122 int flags;
124 if (!ioctl(fd, EXT2_IOC_GETFLAGS, &flags)) {
125 flags &= ~EXT2_IMMUTABLE_FL;
126 ioctl(fd, EXT2_IOC_SETFLAGS, &flags);
128 break;
130 case VFAT:
132 uint32_t attr = 0x00; /* Clear all attributes */
133 ioctl(fd, FAT_IOCTL_SET_ATTRIBUTES, &attr);
134 break;
136 default:
137 break;
139 fchmod(fd, st.st_mode | S_IWUSR);
143 void set_attributes(int fd)
145 struct stat st;
147 if (!fstat(fd, &st)) {
148 fchmod(fd, st.st_mode & (S_IRUSR | S_IRGRP | S_IROTH));
149 switch (fs_type) {
150 case EXT2:
152 int flags;
154 if (st.st_uid == 0 && !ioctl(fd, EXT2_IOC_GETFLAGS, &flags)) {
155 flags |= EXT2_IMMUTABLE_FL;
156 ioctl(fd, EXT2_IOC_SETFLAGS, &flags);
158 break;
160 case VFAT:
162 uint32_t attr = 0x07; /* Hidden+System+Readonly */
163 ioctl(fd, FAT_IOCTL_SET_ATTRIBUTES, &attr);
164 break;
166 default:
167 break;
172 /* New FIEMAP based mapping */
173 static int sectmap_fie(int fd, sector_t *sectors, int nsectors)
175 struct fiemap *fm;
176 struct fiemap_extent *fe;
177 unsigned int i, nsec;
178 sector_t sec, *secp, *esec;
179 struct stat st;
180 uint64_t maplen;
182 if (fstat(fd, &st))
183 return -1;
185 fm = alloca(sizeof(struct fiemap)
186 + nsectors * sizeof(struct fiemap_extent));
188 memset(fm, 0, sizeof *fm);
190 maplen = (uint64_t)nsectors << SECTOR_SHIFT;
191 if (maplen > (uint64_t)st.st_size)
192 maplen = st.st_size;
194 fm->fm_start = 0;
195 fm->fm_length = maplen;
196 fm->fm_flags = FIEMAP_FLAG_SYNC;
197 fm->fm_extent_count = nsectors;
199 if (ioctl(fd, FS_IOC_FIEMAP, fm))
200 return -1;
202 memset(sectors, 0, nsectors * sizeof *sectors);
203 esec = sectors + nsectors;
205 fe = fm->fm_extents;
207 if (fm->fm_mapped_extents < 1 ||
208 !(fe[fm->fm_mapped_extents-1].fe_flags & FIEMAP_EXTENT_LAST))
209 return -1;
211 for (i = 0; i < fm->fm_mapped_extents; i++) {
212 if (fe->fe_flags & FIEMAP_EXTENT_LAST) {
213 /* If this is the *final* extent, pad the length */
214 fe->fe_length = (fe->fe_length + SECTOR_SIZE - 1)
215 & ~(SECTOR_SIZE - 1);
218 if ((fe->fe_logical | fe->fe_physical| fe->fe_length) &
219 (SECTOR_SIZE - 1))
220 return -1;
222 if (fe->fe_flags & (FIEMAP_EXTENT_UNKNOWN|
223 FIEMAP_EXTENT_DELALLOC|
224 FIEMAP_EXTENT_ENCODED|
225 FIEMAP_EXTENT_DATA_ENCRYPTED|
226 FIEMAP_EXTENT_UNWRITTEN))
227 return -1;
229 secp = sectors + (fe->fe_logical >> SECTOR_SHIFT);
230 sec = fe->fe_physical >> SECTOR_SHIFT;
231 nsec = fe->fe_length >> SECTOR_SHIFT;
233 while (nsec--) {
234 if (secp >= esec)
235 break;
236 *secp++ = sec++;
239 fe++;
242 return 0;
245 /* Legacy FIBMAP based mapping */
246 static int sectmap_fib(int fd, sector_t *sectors, int nsectors)
248 unsigned int blk, nblk;
249 unsigned int i;
250 unsigned int blksize;
251 sector_t sec;
253 /* Get block size */
254 if (ioctl(fd, FIGETBSZ, &blksize))
255 return -1;
257 /* Number of sectors per block */
258 blksize >>= SECTOR_SHIFT;
260 nblk = 0;
261 while (nsectors) {
262 blk = nblk++;
263 if (ioctl(fd, FIBMAP, &blk))
264 return -1;
266 sec = (sector_t)blk * blksize;
267 for (i = 0; i < blksize; i++) {
268 *sectors++ = sec++;
269 if (! --nsectors)
270 break;
274 return 0;
278 * Produce file map
280 int sectmap(int fd, sector_t *sectors, int nsectors)
282 if (!sectmap_fie(fd, sectors, nsectors))
283 return 0;
285 return sectmap_fib(fd, sectors, nsectors);