xref: /illumos-gate/usr/src/common/fs/bootfsops.c (revision 66582b606a8194f7f3ba5b3a3a6dca5b0d346361)
1 /*
2  * This file and its contents are supplied under the terms of the
3  * Common Development and Distribution License ("CDDL"), version 1.0.
4  * You may only use this file in accordance with the terms of version
5  * 1.0 of the CDDL.
6  *
7  * A full copy of the text of the CDDL should have accompanied this
8  * source.  A copy of the CDDL is also available via the Internet at
9  * http://www.illumos.org/license/CDDL.
10  */
11 
12 /*
13  * Copyright 2013 Joyent, Inc.  All rights reserved.
14  */
15 
16 #include <sys/bootconf.h>
17 #include <sys/types.h>
18 #include <sys/param.h>
19 #include <sys/vnode.h>
20 #include <sys/fs/ufs_fsdir.h>
21 #include <sys/fs/ufs_fs.h>
22 #include <sys/fs/ufs_inode.h>
23 #include <sys/sysmacros.h>
24 #include <sys/bootvfs.h>
25 #include <sys/bootinfo.h>
26 #include <sys/filep.h>
27 
28 #ifdef	_BOOT
29 #include "../common/util.h"
30 #else
31 #include <sys/sunddi.h>
32 #endif
33 
34 #define	MAX_FILES	MAX_BOOT_MODULES
35 #define	MAX_FDS		256
36 
37 extern void *bkmem_alloc(size_t);
38 extern void bkmem_free(void *, size_t);
39 
40 /*
41  * TODO: Replace these declarations with inclusion of the ordinary userland
42  * bootfs headers once they're available.
43  */
44 typedef struct bfile {
45 	char bf_name[MAXPATHLEN];
46 	caddr_t bf_addr;
47 	size_t bf_size;
48 	struct bfile *bf_next;
49 	uint64_t bf_ino;
50 } bfile_t;
51 
52 typedef struct bf_fd {
53 	bfile_t *fd_file;
54 	off_t fd_pos;
55 } bf_fd_t;
56 
57 static bfile_t *head;
58 static uint_t init_done;
59 static bf_fd_t fds[MAX_FDS];
60 
61 static char cpath[MAXPATHLEN];	/* For canonicalising filenames */
62 
63 static void bbootfs_closeall(int);
64 
65 static void
66 canonicalise(const char *fn, char *out)
67 {
68 	const char *p;
69 	char *q, *s;
70 	char *last;
71 	char *oc;
72 	int is_slash = 0;
73 	static char scratch[MAXPATHLEN];
74 
75 	if (fn == NULL) {
76 		*out = '\0';
77 		return;
78 	}
79 
80 	/*
81 	 * Remove leading slashes and condense all multiple slashes into one.
82 	 */
83 	p = fn;
84 	while (*p == '/')
85 		++p;
86 
87 	for (q = scratch; *p != '\0'; p++) {
88 		if (*p == '/' && !is_slash) {
89 			*q++ = '/';
90 			is_slash = 1;
91 		} else if (*p != '/') {
92 			*q++ = *p;
93 			is_slash = 0;
94 		}
95 	}
96 	*q = '\0';
97 
98 	if (strncmp(scratch, "system/boot/", 12) == 0 ||
99 	    strcmp(scratch, "system/boot") == 0) {
100 		s = scratch + 12;
101 	} else {
102 		s = scratch;
103 	}
104 
105 	for (last = strsep(&s, "/"), q = oc = out; last != NULL;
106 	    last = strsep(&s, "/")) {
107 		if (strcmp(last, ".") == 0)
108 			continue;
109 		if (strcmp(last, "..") == 0) {
110 			for (oc = q; oc > out && *oc != '/'; oc--)
111 				;
112 			q = oc;
113 			continue;
114 		}
115 		if (q > out)
116 			*q++ = '/';
117 		q += snprintf(q, MAXPATHLEN - (q - out), "%s", last);
118 	}
119 
120 	*q = '\0';
121 }
122 
123 /* ARGSUSED */
124 static int
125 bbootfs_mountroot(char *str)
126 {
127 	return (-1);
128 }
129 
130 static int
131 bbootfs_unmountroot(void)
132 {
133 	return (-1);
134 }
135 
136 static int
137 bbootfs_init(void)
138 {
139 	bfile_t *fp;
140 	char propname[32];
141 	uint64_t propval;
142 	uint_t i;
143 
144 	for (i = 0; i < MAX_FILES; i++) {
145 		(void) snprintf(propname, sizeof (propname),
146 		    "module-name-%u", i);
147 		if (do_bsys_getproplen(NULL, propname) < 0)
148 			break;
149 
150 		if ((fp = bkmem_alloc(sizeof (bfile_t))) == NULL) {
151 			bbootfs_closeall(1);
152 			return (-1);
153 		}
154 
155 		(void) do_bsys_getprop(NULL, propname, cpath);
156 		canonicalise(cpath, fp->bf_name);
157 
158 		(void) snprintf(propname, sizeof (propname),
159 		    "module-addr-%u", i);
160 		if (do_bsys_getproplen(NULL, propname) != sizeof (uint64_t)) {
161 			bkmem_free(fp, sizeof (bfile_t));
162 			continue;
163 		}
164 		(void) do_bsys_getprop(NULL, propname, &propval);
165 		fp->bf_addr = (void *)(uintptr_t)propval;
166 
167 		(void) snprintf(propname, sizeof (propname),
168 		    "module-size-%u", i);
169 		if (do_bsys_getproplen(NULL, propname) != sizeof (uint64_t)) {
170 			bkmem_free(fp, sizeof (bfile_t));
171 			continue;
172 		}
173 		(void) do_bsys_getprop(NULL, propname, &propval);
174 		fp->bf_size = (size_t)propval;
175 		fp->bf_ino = i;
176 
177 		fp->bf_next = head;
178 		head = fp;
179 	}
180 
181 	return (0);
182 }
183 
184 /*ARGSUSED*/
185 static int
186 bbootfs_open(char *fn, int flags)
187 {
188 	uint_t i;
189 	bfile_t *fp;
190 
191 	if (!init_done) {
192 		if (bbootfs_init() != 0)
193 			return (-1);
194 
195 		init_done = 1;
196 	}
197 
198 	canonicalise(fn, cpath);
199 
200 	for (fp = head; fp != NULL; fp = fp->bf_next) {
201 		if (strcmp(fp->bf_name, cpath) == 0)
202 			break;
203 	}
204 
205 	if (fp == NULL)
206 		return (-1);
207 
208 	for (i = 0; i < MAX_FDS; i++) {
209 		if (fds[i].fd_file == NULL) {
210 			fds[i].fd_file = fp;
211 			fds[i].fd_pos = 0;
212 			return (i);
213 		}
214 	}
215 
216 	return (-1);
217 }
218 
219 static int
220 bbootfs_close(int fd)
221 {
222 	if (fds[fd].fd_file == NULL)
223 		return (-1);
224 
225 	fds[fd].fd_file = NULL;
226 	fds[fd].fd_pos = 0;
227 
228 	return (0);
229 }
230 
231 static ssize_t
232 bbootfs_read(int fd, caddr_t buf, size_t size)
233 {
234 	ssize_t len;
235 	bf_fd_t *fdp = &fds[fd];
236 
237 	if (fdp->fd_file == NULL)
238 		return (-1);
239 
240 	if (fdp->fd_pos >= fdp->fd_file->bf_size)
241 		return (-1);
242 
243 	if (fdp->fd_pos + size > fdp->fd_file->bf_size)
244 		len = fdp->fd_file->bf_size - fdp->fd_pos;
245 	else
246 		len = size;
247 
248 	bcopy(fdp->fd_file->bf_addr + fdp->fd_pos, buf, len);
249 
250 	fdp->fd_pos += len;
251 
252 	return (len);
253 }
254 
255 static off_t
256 bbootfs_lseek(int fd, off_t addr, int whence)
257 {
258 	bf_fd_t *fdp = &fds[fd];
259 
260 	if (fdp->fd_file == NULL)
261 		return (-1);
262 
263 	switch (whence) {
264 	case SEEK_CUR:
265 		fdp->fd_pos += addr;
266 		break;
267 	case SEEK_SET:
268 		fdp->fd_pos = addr;
269 		break;
270 	case SEEK_END:
271 		fdp->fd_pos = fdp->fd_file->bf_size;
272 		break;
273 	default:
274 		return (-1);
275 	}
276 
277 	return (0);
278 }
279 
280 static int
281 bbootfs_fstat(int fd, struct bootstat *bsp)
282 {
283 	bf_fd_t *fdp = &fds[fd];
284 
285 	if (fdp->fd_file == NULL)
286 		return (-1);
287 
288 	bsp->st_dev = 1;
289 	bsp->st_ino = fdp->fd_file->bf_ino;
290 	bsp->st_mode = 0444;
291 	bsp->st_nlink = 1;
292 	bsp->st_uid = bsp->st_gid = 0;
293 	bsp->st_rdev = 0;
294 	bsp->st_size = fdp->fd_file->bf_size;
295 	bsp->st_blksize = 1;
296 	bsp->st_blocks = fdp->fd_file->bf_size;
297 	(void) strcpy(bsp->st_fstype, "bootfs");
298 
299 	return (0);
300 }
301 
302 /* ARGSUSED */
303 static void
304 bbootfs_closeall(int flag)
305 {
306 	bfile_t *fp;
307 
308 	while (head != NULL) {
309 		fp = head;
310 		head = head->bf_next;
311 
312 		bkmem_free(fp, sizeof (bfile_t));
313 	}
314 
315 	init_done = 0;
316 }
317 
318 struct boot_fs_ops bbootfs_ops = {
319 	"bootfs",
320 	bbootfs_mountroot,
321 	bbootfs_unmountroot,
322 	bbootfs_open,
323 	bbootfs_close,
324 	bbootfs_read,
325 	bbootfs_lseek,
326 	bbootfs_fstat,
327 	bbootfs_closeall,
328 	NULL
329 };
330