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