1 /*
2 * Permission is hereby granted, free of charge, to any person obtaining a copy
3 * of this software and associated documentation files (the "Software"), to
4 * deal in the Software without restriction, including without limitation the
5 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
6 * sell copies of the Software, and to permit persons to whom the Software is
7 * furnished to do so, subject to the following conditions:
8 *
9 * The above copyright notice and this permission notice shall be included in
10 * all copies or substantial portions of the Software.
11 *
12 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
13 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
14 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
15 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
16 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
17 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
18 * DEALINGS IN THE SOFTWARE.
19 *
20 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
21 * Use is subject to license terms.
22 */
23
24 #ifndef __sun__
25 #define _XOPEN_SOURCE 500
26 #endif
27 #include <stdlib.h>
28 #include <strings.h>
29 #include <errno.h>
30
31 #include "xenfsimage_grub.h"
32 #include "fsimage_priv.h"
33
34 static char *disk_read_junk;
35
36 typedef struct fsig_data {
37 char fd_buf[FSYS_BUFLEN];
38 } fsig_data_t;
39
40 typedef struct fsig_file_data {
41 char ffd_buf[FSYS_BUFLEN];
42 uint64_t ffd_curpos;
43 uint64_t ffd_filepos;
44 uint64_t ffd_filemax;
45 int ffd_int1;
46 int ffd_int2;
47 int ffd_errnum;
48 } fsig_file_data_t;
49
50 fsi_file_t *
fsig_file_alloc(fsi_t * fsi)51 fsig_file_alloc(fsi_t *fsi)
52 {
53 fsi_file_t *ffi;
54 fsig_file_data_t *data = malloc(sizeof (fsig_file_data_t));
55
56 if (data == NULL)
57 return (NULL);
58
59 bzero(data, sizeof (fsig_file_data_t));
60 bcopy(fsig_fs_buf(fsi), data->ffd_buf, FSYS_BUFLEN);
61
62 if ((ffi = fsip_file_alloc(fsi, data)) == NULL) {
63 free(data);
64 return (NULL);
65 }
66
67 return (ffi);
68 }
69
70 void *
fsig_fs_buf(fsi_t * fsi)71 fsig_fs_buf(fsi_t *fsi)
72 {
73 fsig_data_t *data = fsip_fs_data(fsi);
74 return ((void *)data->fd_buf);
75 }
76
77 void *
fsig_file_buf(fsi_file_t * ffi)78 fsig_file_buf(fsi_file_t *ffi)
79 {
80 fsig_file_data_t *data = fsip_file_data(ffi);
81 return ((void *)data->ffd_buf);
82 }
83
84 uint64_t *
fsig_filepos(fsi_file_t * ffi)85 fsig_filepos(fsi_file_t *ffi)
86 {
87 fsig_file_data_t *data = fsip_file_data(ffi);
88 return (&data->ffd_filepos);
89 }
90
91 uint64_t *
fsig_filemax(fsi_file_t * ffi)92 fsig_filemax(fsi_file_t *ffi)
93 {
94 fsig_file_data_t *data = fsip_file_data(ffi);
95 return (&data->ffd_filemax);
96 }
97
98 int *
fsig_int1(fsi_file_t * ffi)99 fsig_int1(fsi_file_t *ffi)
100 {
101 fsig_file_data_t *data = fsip_file_data(ffi);
102 return (&data->ffd_int1);
103 }
104
105 int *
fsig_int2(fsi_file_t * ffi)106 fsig_int2(fsi_file_t *ffi)
107 {
108 fsig_file_data_t *data = fsip_file_data(ffi);
109 return (&data->ffd_int2);
110 }
111
112 int *
fsig_errnum(fsi_file_t * ffi)113 fsig_errnum(fsi_file_t *ffi)
114 {
115 fsig_file_data_t *data = fsip_file_data(ffi);
116 return (&data->ffd_errnum);
117 }
118
119 char **
fsig_disk_read_junk(void)120 fsig_disk_read_junk(void)
121 {
122 return (&disk_read_junk);
123 }
124
125 #if defined(__i386__) || defined(__x86_64__)
126
127 #ifdef __amd64
128 #define BSF "bsfq"
129 #else
130 #define BSF "bsfl"
131 #endif
132 unsigned long
fsig_log2(unsigned long word)133 fsig_log2 (unsigned long word)
134 {
135 __asm__ (BSF " %1,%0"
136 : "=r" (word)
137 : "r" (word));
138 return word;
139 }
140
141 #else /* Unoptimized */
142
143 unsigned long
fsig_log2(unsigned long word)144 fsig_log2 (unsigned long word)
145 {
146 unsigned long result = 0;
147
148 while (!(word & 1UL))
149 {
150 result++;
151 word >>= 1;
152 }
153 return result;
154 }
155 #endif
156
157 int
fsig_devread(fsi_file_t * ffi,unsigned int sector,unsigned int offset,unsigned int bufsize,char * buf)158 fsig_devread(fsi_file_t *ffi, unsigned int sector, unsigned int offset,
159 unsigned int bufsize, char *buf)
160 {
161 off_t off;
162 ssize_t ret;
163 int n, r;
164 char tmp[SECTOR_SIZE];
165
166 off = ffi->ff_fsi->f_off + ((off_t)sector * SECTOR_SIZE) + offset;
167
168 /*
169 * Make reads from a raw disk sector-aligned. This is a requirement
170 * for NetBSD. Split the read up into to three parts to meet this
171 * requirement.
172 */
173
174 n = (off & (SECTOR_SIZE - 1));
175 if (n > 0) {
176 r = SECTOR_SIZE - n;
177 if (r > bufsize)
178 r = bufsize;
179 ret = pread(ffi->ff_fsi->f_fd, tmp, SECTOR_SIZE, off - n);
180 if (ret < n + r)
181 return (0);
182 memcpy(buf, tmp + n, r);
183 buf += r;
184 bufsize -= r;
185 off += r;
186 }
187
188 n = (bufsize & ~(SECTOR_SIZE - 1));
189 if (n > 0) {
190 ret = pread(ffi->ff_fsi->f_fd, buf, n, off);
191 if (ret < n)
192 return (0);
193 buf += n;
194 bufsize -= n;
195 off += n;
196 }
197 if (bufsize > 0) {
198 ret = pread(ffi->ff_fsi->f_fd, tmp, SECTOR_SIZE, off);
199 if (ret < bufsize)
200 return (0);
201 memcpy(buf, tmp, bufsize);
202 }
203
204 return (1);
205 }
206
207 int
fsig_substring(const char * s1,const char * s2)208 fsig_substring(const char *s1, const char *s2)
209 {
210 while (*s1 == *s2) {
211 if (*s1 == '\0')
212 return (0);
213 s1++;
214 s2++;
215 }
216
217 if (*s1 == '\0')
218 return (-1);
219
220 return (1);
221 }
222
223 static int
fsig_mount(fsi_t * fsi,const char * path,const char * options)224 fsig_mount(fsi_t *fsi, const char *path, const char *options)
225 {
226 fsig_plugin_ops_t *ops = fsi->f_plugin->fp_data;
227 fsi_file_t *ffi;
228 fsi->f_data = malloc(sizeof (fsig_data_t));
229
230 if (fsi->f_data == NULL)
231 return (-1);
232
233 if ((ffi = fsig_file_alloc(fsi)) == NULL) {
234 free(fsi->f_data);
235 fsi->f_data = NULL;
236 return (-1);
237 }
238
239 bzero(fsi->f_data, sizeof (fsig_data_t));
240
241 if (!ops->fpo_mount(ffi, options)) {
242 fsip_file_free(ffi);
243 fsi_bootstring_free(fsi);
244 free(fsi->f_data);
245 fsi->f_data = NULL;
246 return (-1);
247 }
248
249 bcopy(fsig_file_buf(ffi), fsig_fs_buf(fsi), FSYS_BUFLEN);
250 fsip_file_free(ffi);
251 return (0);
252 }
253
254 static int
fsig_umount(fsi_t * fsi)255 fsig_umount(fsi_t *fsi)
256 {
257 fsi_bootstring_free(fsi);
258 free(fsi->f_data);
259 return (0);
260 }
261
262 static fsi_file_t *
fsig_open(fsi_t * fsi,const char * name)263 fsig_open(fsi_t *fsi, const char *name)
264 {
265 fsig_plugin_ops_t *ops = fsi->f_plugin->fp_data;
266 char *path = strdup(name);
267 fsi_file_t *ffi = NULL;
268
269 if (path == NULL || (ffi = fsig_file_alloc(fsi)) == NULL)
270 goto out;
271
272 if (ops->fpo_dir(ffi, path) == 0) {
273 fsip_file_free(ffi);
274 ffi = NULL;
275 errno = ENOENT;
276 }
277
278 out:
279 free(path);
280 return (ffi);
281 }
282
283 static ssize_t
fsig_pread(fsi_file_t * ffi,void * buf,size_t nbytes,uint64_t off)284 fsig_pread(fsi_file_t *ffi, void *buf, size_t nbytes, uint64_t off)
285 {
286 fsig_plugin_ops_t *ops = ffi->ff_fsi->f_plugin->fp_data;
287 fsig_file_data_t *data = fsip_file_data(ffi);
288
289 data->ffd_filepos = off;
290
291 if (data->ffd_filepos >= data->ffd_filemax)
292 return (0);
293
294 /* FIXME: check */
295 if (data->ffd_filepos + nbytes > data->ffd_filemax)
296 nbytes = data->ffd_filemax - data->ffd_filepos;
297
298 errnum = 0;
299 return (ops->fpo_read(ffi, buf, nbytes));
300 }
301
302 static ssize_t
fsig_read(fsi_file_t * ffi,void * buf,size_t nbytes)303 fsig_read(fsi_file_t *ffi, void *buf, size_t nbytes)
304 {
305 fsig_file_data_t *data = fsip_file_data(ffi);
306 ssize_t ret;
307
308 ret = fsig_pread(ffi, buf, nbytes, data->ffd_curpos);
309 data->ffd_curpos = data->ffd_filepos;
310 return (ret);
311 }
312
313 static int
fsig_close(fsi_file_t * ffi)314 fsig_close(fsi_file_t *ffi)
315 {
316 free(ffi->ff_data);
317 fsip_file_free(ffi);
318 return (0);
319 }
320
321 static fsi_plugin_ops_t fsig_grub_ops = {
322 .fpo_version = FSIMAGE_PLUGIN_VERSION,
323 .fpo_mount = fsig_mount,
324 .fpo_umount = fsig_umount,
325 .fpo_open = fsig_open,
326 .fpo_read = fsig_read,
327 .fpo_pread = fsig_pread,
328 .fpo_close = fsig_close
329 };
330
331 fsi_plugin_ops_t *
fsig_init(fsi_plugin_t * plugin,fsig_plugin_ops_t * ops)332 fsig_init(fsi_plugin_t *plugin, fsig_plugin_ops_t *ops)
333 {
334 if (ops->fpo_version > FSIMAGE_PLUGIN_VERSION)
335 return (NULL);
336
337 plugin->fp_data = ops;
338
339 return (&fsig_grub_ops);
340 }
341