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 2006 Sun Microsystems, Inc.  All rights reserved.
21  * Use is subject to license terms.
22  */
23 
24 #include <stdlib.h>
25 #include <stdio.h>
26 #include <strings.h>
27 #include <string.h>
28 #include <dirent.h>
29 #include <dlfcn.h>
30 #include <errno.h>
31 
32 #include "xenfsimage_plugin.h"
33 #include "fsimage_priv.h"
34 
35 static fsi_plugin_t *plugins;
36 
37 void
fsip_fs_set_data(fsi_t * fsi,void * data)38 fsip_fs_set_data(fsi_t *fsi, void *data)
39 {
40 	fsi->f_data = data;
41 }
42 
43 fsi_file_t *
fsip_file_alloc(fsi_t * fsi,void * data)44 fsip_file_alloc(fsi_t *fsi, void *data)
45 {
46 	fsi_file_t *ffi = malloc(sizeof (fsi_file_t));
47 	if (ffi == NULL)
48 		return (NULL);
49 
50 	bzero(ffi, sizeof (fsi_file_t));
51 
52 	ffi->ff_fsi = fsi;
53 	ffi->ff_data = data;
54 	return (ffi);
55 }
56 
57 void
fsip_file_free(fsi_file_t * ffi)58 fsip_file_free(fsi_file_t *ffi)
59 {
60 	free(ffi);
61 }
62 
63 fsi_t *
fsip_fs(fsi_file_t * ffi)64 fsip_fs(fsi_file_t *ffi)
65 {
66 	return (ffi->ff_fsi);
67 }
68 
69 uint64_t
fsip_fs_offset(fsi_t * fsi)70 fsip_fs_offset(fsi_t *fsi)
71 {
72 	return (fsi->f_off);
73 }
74 
75 void *
fsip_fs_data(fsi_t * fsi)76 fsip_fs_data(fsi_t *fsi)
77 {
78 	return (fsi->f_data);
79 }
80 
81 void *
fsip_file_data(fsi_file_t * ffi)82 fsip_file_data(fsi_file_t *ffi)
83 {
84 	return (ffi->ff_data);
85 }
86 
init_plugin(const char * lib)87 static int init_plugin(const char *lib)
88 {
89 	fsi_plugin_init_t init;
90 	fsi_plugin_t *fp = malloc(sizeof (fsi_plugin_t));
91 
92 	if (fp == NULL)
93 		return (-1);
94 
95 	bzero(fp, sizeof (fsi_plugin_t));
96 
97 	if ((fp->fp_dlh = dlopen(lib, RTLD_LAZY | RTLD_LOCAL)) == NULL) {
98 		free(fp);
99 		return (0);
100 	}
101 
102 	init = dlsym(fp->fp_dlh, "fsi_init_plugin");
103 
104 	if (init == NULL)
105 		goto fail;
106 
107 	fp->fp_ops = init(FSIMAGE_PLUGIN_VERSION, fp, &fp->fp_name);
108 	if (fp->fp_ops == NULL ||
109 	    fp->fp_ops->fpo_version > FSIMAGE_PLUGIN_VERSION)
110 		goto fail;
111 
112 	fp->fp_next = plugins;
113 	plugins = fp;
114 
115 	return (0);
116 fail:
117 	(void) dlclose(fp->fp_dlh);
118 	free(fp);
119 	return (-1);
120 }
121 
load_plugins(void)122 static int load_plugins(void)
123 {
124 	const char *fsdir = getenv("XEN_FSIMAGE_FSDIR");
125 	struct dirent *dp = NULL;
126 	DIR *dir = NULL;
127 	char *tmp = NULL;
128 	size_t name_max;
129 	int err;
130 	int ret = -1;
131 
132 	if (fsdir == NULL)
133 		fsdir = FSIMAGE_FSDIR;
134 
135 	if ((name_max = pathconf(fsdir, _PC_NAME_MAX)) == -1)
136 		goto fail;
137 
138 	if ((tmp = malloc(name_max + 1)) == NULL)
139 		goto fail;
140 
141 	if ((dir = opendir(fsdir)) == NULL)
142 		goto fail;
143 
144 	for (;;) {
145 		errno = 0;
146 		dp = readdir(dir);
147 
148 		if (dp == NULL && errno != 0)
149 			goto fail;
150 
151 		if (dp == NULL)
152 			break;
153 
154 		if (strcmp(dp->d_name, ".") == 0)
155 			continue;
156 		if (strcmp(dp->d_name, "..") == 0)
157 			continue;
158 
159 		(void) snprintf(tmp, name_max, "%s/%s/fsimage.so", fsdir,
160 			dp->d_name);
161 
162 		if (init_plugin(tmp) != 0)
163 			goto fail;
164 	}
165 
166 	ret = 0;
167 
168 fail:
169 	err = errno;
170 	if (dir != NULL)
171 		(void) closedir(dir);
172 	free(tmp);
173 	free(dp);
174 	errno = err;
175 	return (ret);
176 }
177 
find_plugin(fsi_t * fsi,const char * path,const char * options)178 int find_plugin(fsi_t *fsi, const char *path, const char *options)
179 {
180 	fsi_plugin_t *fp;
181 	int ret = 0;
182 
183 	if (plugins == NULL && (ret = load_plugins()) != 0)
184 		goto out;
185 
186 	for (fp = plugins; fp != NULL; fp = fp->fp_next) {
187 		fsi->f_plugin = fp;
188 		if (fp->fp_ops->fpo_mount(fsi, path, options) == 0)
189 			goto out;
190 	}
191 
192 	ret = -1;
193 	errno = ENOTSUP;
194 out:
195 	return (ret);
196 }
197