1 | 1 |
new file mode 100644 |
... | ... |
@@ -0,0 +1,349 @@ |
0 |
+package devmapper |
|
1 |
+ |
|
2 |
+/* |
|
3 |
+#cgo LDFLAGS: -L. -ldevmapper |
|
4 |
+#include <stdio.h> |
|
5 |
+#include <stdlib.h> |
|
6 |
+#include <unistd.h> |
|
7 |
+#include <libdevmapper.h> |
|
8 |
+#include <linux/loop.h> |
|
9 |
+#include <sys/types.h> |
|
10 |
+#include <sys/stat.h> |
|
11 |
+#include <fcntl.h> |
|
12 |
+#include <sys/ioctl.h> |
|
13 |
+#include <linux/fs.h> |
|
14 |
+#include <errno.h> |
|
15 |
+ |
|
16 |
+static char * |
|
17 |
+attach_loop_device(const char *filename, int *loop_fd_out) |
|
18 |
+{ |
|
19 |
+ struct loop_info64 loopinfo = { 0 }; |
|
20 |
+ struct stat st; |
|
21 |
+ char buf[64]; |
|
22 |
+ int i, loop_fd, fd, start_index; |
|
23 |
+ char *loopname; |
|
24 |
+ |
|
25 |
+ *loop_fd_out = -1; |
|
26 |
+ |
|
27 |
+ start_index = 0; |
|
28 |
+ fd = open("/dev/loop-control", O_RDONLY); |
|
29 |
+ if (fd == 0) { |
|
30 |
+ start_index = ioctl(fd, LOOP_CTL_GET_FREE); |
|
31 |
+ close(fd); |
|
32 |
+ |
|
33 |
+ if (start_index < 0) |
|
34 |
+ start_index = 0; |
|
35 |
+ } |
|
36 |
+ |
|
37 |
+ fd = open(filename, O_RDWR); |
|
38 |
+ if (fd < 0) { |
|
39 |
+ return NULL; |
|
40 |
+ } |
|
41 |
+ |
|
42 |
+ loop_fd = -1; |
|
43 |
+ for (i = start_index ; loop_fd < 0 ; i++ ) { |
|
44 |
+ if (sprintf(buf, "/dev/loop%d", i) < 0) { |
|
45 |
+ close(fd); |
|
46 |
+ return NULL; |
|
47 |
+ } |
|
48 |
+ |
|
49 |
+ if (stat(buf, &st) || !S_ISBLK(st.st_mode)) { |
|
50 |
+ close(fd); |
|
51 |
+ return NULL; |
|
52 |
+ } |
|
53 |
+ |
|
54 |
+ loop_fd = open(buf, O_RDWR); |
|
55 |
+ if (loop_fd < 0 && errno == ENOENT) { |
|
56 |
+ close(fd); |
|
57 |
+ fprintf (stderr, "no available loopback device!"); |
|
58 |
+ return NULL; |
|
59 |
+ } else if (loop_fd < 0) |
|
60 |
+ continue; |
|
61 |
+ |
|
62 |
+ if (ioctl (loop_fd, LOOP_SET_FD, (void *)(size_t)fd) < 0) { |
|
63 |
+ close(loop_fd); |
|
64 |
+ loop_fd = -1; |
|
65 |
+ if (errno != EBUSY) { |
|
66 |
+ close (fd); |
|
67 |
+ fprintf (stderr, "cannot set up loopback device %s", buf); |
|
68 |
+ return NULL; |
|
69 |
+ } |
|
70 |
+ continue; |
|
71 |
+ } |
|
72 |
+ |
|
73 |
+ close (fd); |
|
74 |
+ |
|
75 |
+ strncpy((char*)loopinfo.lo_file_name, buf, LO_NAME_SIZE); |
|
76 |
+ loopinfo.lo_offset = 0; |
|
77 |
+ loopinfo.lo_flags = LO_FLAGS_AUTOCLEAR; |
|
78 |
+ |
|
79 |
+ if (ioctl(loop_fd, LOOP_SET_STATUS64, &loopinfo) < 0) { |
|
80 |
+ ioctl(loop_fd, LOOP_CLR_FD, 0); |
|
81 |
+ close(loop_fd); |
|
82 |
+ fprintf (stderr, "cannot set up loopback device info"); |
|
83 |
+ return NULL; |
|
84 |
+ } |
|
85 |
+ |
|
86 |
+ loopname = strdup(buf); |
|
87 |
+ if (loopname == NULL) { |
|
88 |
+ close(loop_fd); |
|
89 |
+ return NULL; |
|
90 |
+ } |
|
91 |
+ |
|
92 |
+ *loop_fd_out = loop_fd; |
|
93 |
+ return loopname; |
|
94 |
+ } |
|
95 |
+ return NULL; |
|
96 |
+} |
|
97 |
+ |
|
98 |
+static int64_t |
|
99 |
+get_block_size(int fd) |
|
100 |
+{ |
|
101 |
+ uint64_t size; |
|
102 |
+ if (ioctl(fd, BLKGETSIZE64, &size) == -1) |
|
103 |
+ return -1; |
|
104 |
+ return (int64_t)size; |
|
105 |
+} |
|
106 |
+ |
|
107 |
+ |
|
108 |
+*/ |
|
109 |
+import "C" |
|
110 |
+import "unsafe" |
|
111 |
+import "fmt" |
|
112 |
+import "runtime" |
|
113 |
+import "os" |
|
114 |
+ |
|
115 |
+func SetDevDir(dir string) error { |
|
116 |
+ c_dir := C.CString(dir) |
|
117 |
+ defer C.free(unsafe.Pointer(c_dir)) |
|
118 |
+ res := C.dm_set_dev_dir(c_dir) |
|
119 |
+ if res != 1 { |
|
120 |
+ return fmt.Errorf("dm_set_dev_dir failed") |
|
121 |
+ } |
|
122 |
+ return nil |
|
123 |
+} |
|
124 |
+ |
|
125 |
+func GetLibraryVersion() (string, error) { |
|
126 |
+ buffer := (*C.char)(C.malloc(128)) |
|
127 |
+ defer C.free(unsafe.Pointer(buffer)) |
|
128 |
+ res := C.dm_get_library_version(buffer, 128) |
|
129 |
+ if res != 1 { |
|
130 |
+ return "", fmt.Errorf("dm_get_library_version failed") |
|
131 |
+ } else { |
|
132 |
+ return C.GoString(buffer), nil |
|
133 |
+ } |
|
134 |
+} |
|
135 |
+ |
|
136 |
+type TaskType int |
|
137 |
+ |
|
138 |
+const ( |
|
139 |
+ DeviceCreate TaskType = iota |
|
140 |
+ DeviceReload |
|
141 |
+ DeviceRemove |
|
142 |
+ DeviceRemoveAll |
|
143 |
+ DeviceSuspend |
|
144 |
+ DeviceResume |
|
145 |
+ DeviceInfo |
|
146 |
+ DeviceDeps |
|
147 |
+ DeviceRename |
|
148 |
+ DeviceVersion |
|
149 |
+ DeviceStatus |
|
150 |
+ DeviceTable |
|
151 |
+ DeviceWaitevent |
|
152 |
+ DeviceList |
|
153 |
+ DeviceClear |
|
154 |
+ DeviceMknodes |
|
155 |
+ DeviceListVersions |
|
156 |
+ DeviceTargetMsg |
|
157 |
+ DeviceSetGeometry |
|
158 |
+) |
|
159 |
+ |
|
160 |
+type Task struct { |
|
161 |
+ unmanaged *C.struct_dm_task |
|
162 |
+} |
|
163 |
+ |
|
164 |
+type Info struct { |
|
165 |
+ Exists int |
|
166 |
+ Suspended int |
|
167 |
+ LiveTable int |
|
168 |
+ InactiveTable int |
|
169 |
+ OpenCount int32 |
|
170 |
+ EventNr uint32 |
|
171 |
+ Major uint32 |
|
172 |
+ Minor uint32 |
|
173 |
+ ReadOnly int |
|
174 |
+ TargetCount int32 |
|
175 |
+} |
|
176 |
+ |
|
177 |
+func (t *Task) destroy() { |
|
178 |
+ if t != nil { |
|
179 |
+ C.dm_task_destroy(t.unmanaged) |
|
180 |
+ runtime.SetFinalizer(t, nil) |
|
181 |
+ } |
|
182 |
+} |
|
183 |
+ |
|
184 |
+func TaskCreate(tasktype TaskType) *Task { |
|
185 |
+ c_task := C.dm_task_create(C.int(int(tasktype))) |
|
186 |
+ if c_task == nil { |
|
187 |
+ return nil |
|
188 |
+ } |
|
189 |
+ task := &Task{c_task} |
|
190 |
+ runtime.SetFinalizer(task, (*Task).destroy) |
|
191 |
+ return task |
|
192 |
+} |
|
193 |
+ |
|
194 |
+func (t *Task) Run() error { |
|
195 |
+ res := C.dm_task_run(t.unmanaged) |
|
196 |
+ if res != 1 { |
|
197 |
+ return fmt.Errorf("dm_task_run failed") |
|
198 |
+ } |
|
199 |
+ return nil |
|
200 |
+} |
|
201 |
+ |
|
202 |
+func (t *Task) SetName(name string) error { |
|
203 |
+ c_name := C.CString(name) |
|
204 |
+ defer C.free(unsafe.Pointer(c_name)) |
|
205 |
+ |
|
206 |
+ res := C.dm_task_set_name(t.unmanaged, c_name) |
|
207 |
+ if res != 1 { |
|
208 |
+ return fmt.Errorf("dm_task_set_name failed") |
|
209 |
+ } |
|
210 |
+ return nil |
|
211 |
+} |
|
212 |
+ |
|
213 |
+func (t *Task) SetMessage(message string) error { |
|
214 |
+ c_message := C.CString(message) |
|
215 |
+ defer C.free(unsafe.Pointer(c_message)) |
|
216 |
+ |
|
217 |
+ res := C.dm_task_set_message(t.unmanaged, c_message) |
|
218 |
+ if res != 1 { |
|
219 |
+ return fmt.Errorf("dm_task_set_message failed") |
|
220 |
+ } |
|
221 |
+ return nil |
|
222 |
+} |
|
223 |
+ |
|
224 |
+func (t *Task) SetSector(sector uint64) error { |
|
225 |
+ res := C.dm_task_set_sector(t.unmanaged, C.uint64_t(sector)) |
|
226 |
+ if res != 1 { |
|
227 |
+ return fmt.Errorf("dm_task_set_add_node failed") |
|
228 |
+ } |
|
229 |
+ return nil |
|
230 |
+} |
|
231 |
+ |
|
232 |
+func (t *Task) SetCookie(cookie *uint32, flags uint16) error { |
|
233 |
+ var c_cookie C.uint32_t |
|
234 |
+ c_cookie = C.uint32_t(*cookie) |
|
235 |
+ res := C.dm_task_set_cookie(t.unmanaged, &c_cookie, C.uint16_t(flags)) |
|
236 |
+ if res != 1 { |
|
237 |
+ return fmt.Errorf("dm_task_set_add_node failed") |
|
238 |
+ } |
|
239 |
+ *cookie = uint32(c_cookie) |
|
240 |
+ return nil |
|
241 |
+} |
|
242 |
+ |
|
243 |
+func (t *Task) SetRo() error { |
|
244 |
+ res := C.dm_task_set_ro(t.unmanaged) |
|
245 |
+ if res != 1 { |
|
246 |
+ return fmt.Errorf("dm_task_set_ro failed") |
|
247 |
+ } |
|
248 |
+ return nil |
|
249 |
+} |
|
250 |
+ |
|
251 |
+func (t *Task) AddTarget(start uint64, size uint64, ttype string, params string) error { |
|
252 |
+ c_ttype := C.CString(ttype) |
|
253 |
+ defer C.free(unsafe.Pointer(c_ttype)) |
|
254 |
+ |
|
255 |
+ c_params := C.CString(params) |
|
256 |
+ defer C.free(unsafe.Pointer(c_params)) |
|
257 |
+ |
|
258 |
+ res := C.dm_task_add_target(t.unmanaged, C.uint64_t(start), C.uint64_t(size), c_ttype, c_params) |
|
259 |
+ if res != 1 { |
|
260 |
+ return fmt.Errorf("dm_task_add_target failed") |
|
261 |
+ } |
|
262 |
+ return nil |
|
263 |
+} |
|
264 |
+ |
|
265 |
+func (t *Task) GetDriverVersion() (string, error) { |
|
266 |
+ buffer := (*C.char)(C.malloc(128)) |
|
267 |
+ defer C.free(unsafe.Pointer(buffer)) |
|
268 |
+ |
|
269 |
+ res := C.dm_task_get_driver_version(t.unmanaged, buffer, 128) |
|
270 |
+ if res != 1 { |
|
271 |
+ return "", fmt.Errorf("dm_task_get_driver_version") |
|
272 |
+ } else { |
|
273 |
+ return C.GoString(buffer), nil |
|
274 |
+ } |
|
275 |
+} |
|
276 |
+ |
|
277 |
+func (t *Task) GetInfo() (*Info, error) { |
|
278 |
+ c_info := C.struct_dm_info{} |
|
279 |
+ res := C.dm_task_get_info(t.unmanaged, &c_info) |
|
280 |
+ if res != 1 { |
|
281 |
+ return nil, fmt.Errorf("dm_task_get_driver_version") |
|
282 |
+ } else { |
|
283 |
+ info := &Info{} |
|
284 |
+ info.Exists = int(c_info.exists) |
|
285 |
+ info.Suspended = int(c_info.suspended) |
|
286 |
+ info.LiveTable = int(c_info.live_table) |
|
287 |
+ info.InactiveTable = int(c_info.inactive_table) |
|
288 |
+ info.OpenCount = int32(c_info.open_count) |
|
289 |
+ info.EventNr = uint32(c_info.event_nr) |
|
290 |
+ info.Major = uint32(c_info.major) |
|
291 |
+ info.Minor = uint32(c_info.minor) |
|
292 |
+ info.ReadOnly = int(c_info.read_only) |
|
293 |
+ info.TargetCount = int32(c_info.target_count) |
|
294 |
+ |
|
295 |
+ return info, nil |
|
296 |
+ } |
|
297 |
+} |
|
298 |
+ |
|
299 |
+func (t *Task) GetNextTarget(next uintptr) (uintptr, uint64, uint64, string, string) { |
|
300 |
+ nextp := unsafe.Pointer(next) |
|
301 |
+ var c_start C.uint64_t |
|
302 |
+ var c_length C.uint64_t |
|
303 |
+ var c_target_type *C.char |
|
304 |
+ var c_params *C.char |
|
305 |
+ |
|
306 |
+ nextp = C.dm_get_next_target(t.unmanaged, nextp, &c_start, &c_length, &c_target_type, &c_params) |
|
307 |
+ |
|
308 |
+ target_type := C.GoString(c_target_type) |
|
309 |
+ params := C.GoString(c_params) |
|
310 |
+ |
|
311 |
+ return uintptr(nextp), uint64(c_start), uint64(c_length), target_type, params |
|
312 |
+} |
|
313 |
+ |
|
314 |
+func AttachLoopDevice(filename string) (*os.File, error) { |
|
315 |
+ c_filename := C.CString(filename) |
|
316 |
+ defer C.free(unsafe.Pointer(c_filename)) |
|
317 |
+ |
|
318 |
+ var fd C.int |
|
319 |
+ res := C.attach_loop_device(c_filename, &fd) |
|
320 |
+ if res == nil { |
|
321 |
+ return nil, fmt.Errorf("error loopback mounting") |
|
322 |
+ } |
|
323 |
+ file := os.NewFile(uintptr(fd), C.GoString(res)) |
|
324 |
+ C.free(unsafe.Pointer(res)) |
|
325 |
+ return file, nil |
|
326 |
+} |
|
327 |
+ |
|
328 |
+func GetBlockDeviceSize(file *os.File) (uint64, error) { |
|
329 |
+ fd := file.Fd() |
|
330 |
+ size := C.get_block_size(C.int(fd)) |
|
331 |
+ if size == -1 { |
|
332 |
+ return 0, fmt.Errorf("Can't get block size") |
|
333 |
+ } |
|
334 |
+ return uint64(size), nil |
|
335 |
+ |
|
336 |
+} |
|
337 |
+ |
|
338 |
+func UdevWait(cookie uint32) error { |
|
339 |
+ res := C.dm_udev_wait(C.uint32_t(cookie)) |
|
340 |
+ if res != 1 { |
|
341 |
+ return fmt.Errorf("Failed to wait on udev cookie %d", cookie) |
|
342 |
+ } |
|
343 |
+ return nil |
|
344 |
+} |
|
345 |
+ |
|
346 |
+func LogInitVerbose(level int) { |
|
347 |
+ C.dm_log_init_verbose(C.int(level)) |
|
348 |
+} |