Browse code

Add libdevmapper wrapper

Alexander Larsson authored on 2013/09/04 18:14:31
Showing 1 changed files
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
+}