extlinux: add a --menu-save option
[profile/ivi/syslinux.git] / libinstaller / syslxcom.c
1 /* ----------------------------------------------------------------------- *
2  *
3  *   Copyright 2010 Intel Corp. - All Rights Reserved
4  *
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.
10  *
11  * ----------------------------------------------------------------------- */
12
13 /*
14  * syslxcom.c
15  *
16  * common functions for extlinux & syslinux installer
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/ioctl.h>
30 #include <sys/stat.h>
31 #include <sys/types.h>
32 #include <sys/mount.h>
33 #include <sys/vfs.h>
34 #include <linux/fs.h>           /* FIGETBSZ, FIBMAP */
35 #include <linux/msdos_fs.h>     /* FAT_IOCTL_SET_ATTRIBUTES */
36 #include "syslxcom.h"
37
38 const char *program;
39
40 int 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 #define EXT2_IMMUTABLE_FL               0x00000010      /* Immutable file */
50
51 /*
52  * ioctl commands
53  */
54 #define EXT2_IOC_GETFLAGS               _IOR('f', 1, long)
55 #define EXT2_IOC_SETFLAGS               _IOW('f', 2, long)
56 #define EXT2_IOC_GETVERSION             _IOR('v', 1, long)
57 #define EXT2_IOC_SETVERSION             _IOW('v', 2, long)
58
59 static void die(const char *msg)
60 {
61     fputs(msg, stderr);
62     exit(1);
63 }
64
65 /*
66  * read/write wrapper functions
67  */
68 ssize_t xpread(int fd, void *buf, size_t count, off_t offset)
69 {
70     char *bufp = (char *)buf;
71     ssize_t rv;
72     ssize_t done = 0;
73
74     while (count) {
75         rv = pread(fd, bufp, count, offset);
76         if (rv == 0) {
77             die("short read");
78         } else if (rv == -1) {
79             if (errno == EINTR) {
80                 continue;
81             } else {
82                 die(strerror(errno));
83             }
84         } else {
85             bufp += rv;
86             offset += rv;
87             done += rv;
88             count -= rv;
89         }
90     }
91
92     return done;
93 }
94
95 ssize_t xpwrite(int fd, const void *buf, size_t count, off_t offset)
96 {
97     const char *bufp = (const char *)buf;
98     ssize_t rv;
99     ssize_t done = 0;
100
101     while (count) {
102         rv = pwrite(fd, bufp, count, offset);
103         if (rv == 0) {
104             die("short write");
105         } else if (rv == -1) {
106             if (errno == EINTR) {
107                 continue;
108             } else {
109                 die(strerror(errno));
110             }
111         } else {
112             bufp += rv;
113             offset += rv;
114             done += rv;
115             count -= rv;
116         }
117     }
118
119     return done;
120 }
121
122 /*
123  * Set and clear file attributes
124  */
125 void clear_attributes(int fd)
126 {
127     struct stat st;
128
129     if (!fstat(fd, &st)) {
130         switch (fs_type) {
131         case EXT2:
132         {
133             int flags;
134
135             if (!ioctl(fd, EXT2_IOC_GETFLAGS, &flags)) {
136                 flags &= ~EXT2_IMMUTABLE_FL;
137                 ioctl(fd, EXT2_IOC_SETFLAGS, &flags);
138             }
139             break;
140         }
141         case VFAT:
142         {
143             uint32_t attr = 0x00; /* Clear all attributes */
144             ioctl(fd, FAT_IOCTL_SET_ATTRIBUTES, &attr);
145             break;
146         }
147         default:
148             break;
149         }
150         fchmod(fd, st.st_mode | S_IWUSR);
151     }
152 }
153
154 void set_attributes(int fd)
155 {
156     struct stat st;
157
158     if (!fstat(fd, &st)) {
159         fchmod(fd, st.st_mode & (S_IRUSR | S_IRGRP | S_IROTH));
160         switch (fs_type) {
161         case EXT2:
162         {
163             int flags;
164
165             if (st.st_uid == 0 && !ioctl(fd, EXT2_IOC_GETFLAGS, &flags)) {
166                 flags |= EXT2_IMMUTABLE_FL;
167                 ioctl(fd, EXT2_IOC_SETFLAGS, &flags);
168             }
169             break;
170         }
171         case VFAT:
172         {
173             uint32_t attr = 0x07; /* Hidden+System+Readonly */
174             ioctl(fd, FAT_IOCTL_SET_ATTRIBUTES, &attr);
175             break;
176         }
177         default:
178             break;
179         }
180     }
181 }
182
183 /*
184  * Produce file map
185  */
186 int sectmap(int fd, uint32_t * sectors, int nsectors)
187 {
188     unsigned int blksize, blk, nblk;
189     unsigned int i;
190
191     /* Get block size */
192     if (ioctl(fd, FIGETBSZ, &blksize))
193         return -1;
194
195     /* Number of sectors per block */
196     blksize >>= SECTOR_SHIFT;
197
198     nblk = 0;
199     while (nsectors) {
200
201         blk = nblk++;
202         dprintf("querying block %u\n", blk);
203         if (ioctl(fd, FIBMAP, &blk))
204             return -1;
205
206         blk *= blksize;
207         for (i = 0; i < blksize; i++) {
208             if (!nsectors)
209                 return 0;
210
211             dprintf("Sector: %10u\n", blk);
212             *sectors++ = blk++;
213             nsectors--;
214         }
215     }
216
217     return 0;
218 }