ruby-libvirt-catphish 0.7.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,490 @@
1
+ /*
2
+ * common.c: Common utilities for the ruby libvirt bindings
3
+ *
4
+ * Copyright (C) 2007,2010 Red Hat Inc.
5
+ * Copyright (C) 2013-2016 Chris Lalancette <clalancette@gmail.com>
6
+ *
7
+ * This library is free software; you can redistribute it and/or
8
+ * modify it under the terms of the GNU Lesser General Public
9
+ * License as published by the Free Software Foundation; either
10
+ * version 2.1 of the License, or (at your option) any later version.
11
+ *
12
+ * This library is distributed in the hope that it will be useful,
13
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
14
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15
+ * Lesser General Public License for more details.
16
+ *
17
+ * You should have received a copy of the GNU Lesser General Public
18
+ * License along with this library; if not, write to the Free Software
19
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20
+ */
21
+
22
+ #ifndef _GNU_SOURCE
23
+ #define _GNU_SOURCE 1
24
+ #endif
25
+ #include <stdio.h>
26
+ #include <ruby.h>
27
+ #include <st.h>
28
+ #include <libvirt/libvirt.h>
29
+ #include <libvirt/virterror.h>
30
+ #include "common.h"
31
+ #include "connect.h"
32
+
33
+ struct rb_exc_new2_arg {
34
+ VALUE error;
35
+ char *msg;
36
+ };
37
+
38
+ static VALUE ruby_libvirt_exc_new2_wrap(VALUE arg)
39
+ {
40
+ struct rb_exc_new2_arg *e = (struct rb_exc_new2_arg *)arg;
41
+
42
+ return rb_exc_new2(e->error, e->msg);
43
+ }
44
+
45
+ VALUE ruby_libvirt_ary_new2_wrap(VALUE arg)
46
+ {
47
+ return rb_ary_new2(*((int *)arg));
48
+ }
49
+
50
+ VALUE ruby_libvirt_ary_push_wrap(VALUE arg)
51
+ {
52
+ struct ruby_libvirt_ary_push_arg *e = (struct ruby_libvirt_ary_push_arg *)arg;
53
+
54
+ return rb_ary_push(e->arr, e->value);
55
+ }
56
+
57
+ VALUE ruby_libvirt_ary_store_wrap(VALUE arg)
58
+ {
59
+ struct ruby_libvirt_ary_store_arg *e = (struct ruby_libvirt_ary_store_arg *)arg;
60
+
61
+ rb_ary_store(e->arr, e->index, e->elem);
62
+
63
+ return Qnil;
64
+ }
65
+
66
+ VALUE ruby_libvirt_str_new2_wrap(VALUE arg)
67
+ {
68
+ char **str = (char **)arg;
69
+
70
+ return rb_str_new2(*str);
71
+ }
72
+
73
+ VALUE ruby_libvirt_str_new_wrap(VALUE arg)
74
+ {
75
+ struct ruby_libvirt_str_new_arg *e = (struct ruby_libvirt_str_new_arg *)arg;
76
+
77
+ return rb_str_new(e->val, e->size);
78
+ }
79
+
80
+ VALUE ruby_libvirt_hash_aset_wrap(VALUE arg)
81
+ {
82
+ struct ruby_libvirt_hash_aset_arg *e = (struct ruby_libvirt_hash_aset_arg *)arg;
83
+
84
+ return rb_hash_aset(e->hash, rb_str_new2(e->name), e->val);
85
+ }
86
+
87
+ VALUE ruby_libvirt_str_new2_and_ary_store_wrap(VALUE arg)
88
+ {
89
+ struct ruby_libvirt_str_new2_and_ary_store_arg *e = (struct ruby_libvirt_str_new2_and_ary_store_arg *)arg;
90
+
91
+ rb_ary_store(e->arr, e->index, rb_str_new2(e->value));
92
+
93
+ return Qnil;
94
+ }
95
+
96
+ void ruby_libvirt_raise_error_if(const int condition, VALUE error,
97
+ const char *method, virConnectPtr conn)
98
+ {
99
+ VALUE ruby_errinfo;
100
+ virErrorPtr err;
101
+ char *msg;
102
+ int rc;
103
+ struct rb_exc_new2_arg arg;
104
+ int exception = 0;
105
+
106
+ if (!condition) {
107
+ return;
108
+ }
109
+
110
+ if (conn == NULL) {
111
+ err = virGetLastError();
112
+ }
113
+ else {
114
+ err = virConnGetLastError(conn);
115
+ }
116
+
117
+ if (err != NULL && err->message != NULL) {
118
+ rc = asprintf(&msg, "Call to %s failed: %s", method, err->message);
119
+ }
120
+ else {
121
+ rc = asprintf(&msg, "Call to %s failed", method);
122
+ }
123
+
124
+ if (rc < 0) {
125
+ /* there's not a whole lot we can do here; try to raise an
126
+ * out-of-memory message */
127
+ rb_memerror();
128
+ }
129
+
130
+ arg.error = error;
131
+ arg.msg = msg;
132
+ ruby_errinfo = rb_protect(ruby_libvirt_exc_new2_wrap, (VALUE)&arg,
133
+ &exception);
134
+ free(msg);
135
+ if (exception) {
136
+ rb_jump_tag(exception);
137
+ }
138
+
139
+ rb_iv_set(ruby_errinfo, "@libvirt_function_name", rb_str_new2(method));
140
+
141
+ if (err != NULL) {
142
+ rb_iv_set(ruby_errinfo, "@libvirt_code", INT2NUM(err->code));
143
+ rb_iv_set(ruby_errinfo, "@libvirt_component", INT2NUM(err->domain));
144
+ rb_iv_set(ruby_errinfo, "@libvirt_level", INT2NUM(err->level));
145
+ if (err->message != NULL) {
146
+ rb_iv_set(ruby_errinfo, "@libvirt_message",
147
+ rb_str_new2(err->message));
148
+ }
149
+ }
150
+
151
+ rb_exc_raise(ruby_errinfo);
152
+ };
153
+
154
+ char *ruby_libvirt_get_cstring_or_null(VALUE arg)
155
+ {
156
+ if (TYPE(arg) == T_NIL) {
157
+ return NULL;
158
+ }
159
+ else if (TYPE(arg) == T_STRING) {
160
+ return StringValueCStr(arg);
161
+ }
162
+ else {
163
+ rb_raise(rb_eTypeError, "wrong argument type (expected String or nil)");
164
+ }
165
+
166
+ return NULL;
167
+ }
168
+
169
+ VALUE ruby_libvirt_new_class(VALUE klass, void *ptr, VALUE conn,
170
+ RUBY_DATA_FUNC free_func)
171
+ {
172
+ VALUE result;
173
+ result = Data_Wrap_Struct(klass, NULL, free_func, ptr);
174
+ rb_iv_set(result, "@connection", conn);
175
+ return result;
176
+ }
177
+
178
+ int ruby_libvirt_is_symbol_or_proc(VALUE handle)
179
+ {
180
+ return ((strcmp(rb_obj_classname(handle), "Symbol") == 0) ||
181
+ (strcmp(rb_obj_classname(handle), "Proc") == 0));
182
+ }
183
+
184
+ /* this is an odd function, because it has massive side-effects.
185
+ * The intended usage of this function is after a list has been collected
186
+ * from a libvirt list function, and now we want to make an array out of it.
187
+ * However, it is possible that the act of creating an array causes an
188
+ * exception, which would lead to a memory leak of the values we got from
189
+ * libvirt. Therefore, this function not only wraps all of the relevant
190
+ * calls with rb_protect, it also frees every individual entry in list after
191
+ * it is done with it. Freeing list itself is left to the callers.
192
+ */
193
+ VALUE ruby_libvirt_generate_list(int num, char **list)
194
+ {
195
+ VALUE result;
196
+ int exception = 0;
197
+ int i, j;
198
+ struct ruby_libvirt_str_new2_and_ary_store_arg arg;
199
+
200
+ i = 0;
201
+
202
+ result = rb_protect(ruby_libvirt_ary_new2_wrap, (VALUE)&num, &exception);
203
+ if (exception) {
204
+ goto exception;
205
+ }
206
+ for (i = 0; i < num; i++) {
207
+ arg.arr = result;
208
+ arg.index = i;
209
+ arg.value = list[i];
210
+ rb_protect(ruby_libvirt_str_new2_and_ary_store_wrap, (VALUE)&arg,
211
+ &exception);
212
+ if (exception) {
213
+ goto exception;
214
+ }
215
+
216
+ xfree(list[i]);
217
+ }
218
+
219
+ return result;
220
+
221
+ exception:
222
+ for (j = i; j < num; j++) {
223
+ xfree(list[j]);
224
+ }
225
+ rb_jump_tag(exception);
226
+
227
+ /* not needed, but here to shut the compiler up */
228
+ return Qnil;
229
+ }
230
+
231
+ void ruby_libvirt_typed_params_to_hash(void *voidparams, int i, VALUE hash)
232
+ {
233
+ virTypedParameterPtr params = (virTypedParameterPtr)voidparams;
234
+ VALUE val;
235
+
236
+ switch (params[i].type) {
237
+ case VIR_TYPED_PARAM_INT:
238
+ val = INT2NUM(params[i].value.i);
239
+ break;
240
+ case VIR_TYPED_PARAM_UINT:
241
+ val = UINT2NUM(params[i].value.ui);
242
+ break;
243
+ case VIR_TYPED_PARAM_LLONG:
244
+ val = LL2NUM(params[i].value.l);
245
+ break;
246
+ case VIR_TYPED_PARAM_ULLONG:
247
+ val = ULL2NUM(params[i].value.ul);
248
+ break;
249
+ case VIR_TYPED_PARAM_DOUBLE:
250
+ val = rb_float_new(params[i].value.d);
251
+ break;
252
+ case VIR_TYPED_PARAM_BOOLEAN:
253
+ val = (params[i].value.b == 0) ? Qfalse : Qtrue;
254
+ break;
255
+ case VIR_TYPED_PARAM_STRING:
256
+ val = rb_str_new2(params[i].value.s);
257
+ break;
258
+ default:
259
+ rb_raise(rb_eArgError, "Invalid parameter type");
260
+ }
261
+
262
+ rb_hash_aset(hash, rb_str_new2(params[i].field), val);
263
+ }
264
+
265
+ VALUE ruby_libvirt_get_parameters(VALUE d, unsigned int flags, void *opaque,
266
+ unsigned int typesize,
267
+ const char *(*nparams_cb)(VALUE d,
268
+ unsigned int flags,
269
+ void *opaque,
270
+ int *nparams),
271
+ const char *(*get_cb)(VALUE d,
272
+ unsigned int flags,
273
+ void *voidparams,
274
+ int *nparams,
275
+ void *opaque),
276
+ void (*hash_set)(void *voidparams, int i,
277
+ VALUE result))
278
+ {
279
+ int nparams = 0;
280
+ void *params;
281
+ VALUE result;
282
+ const char *errname;
283
+ int i;
284
+
285
+ errname = nparams_cb(d, flags, opaque, &nparams);
286
+ ruby_libvirt_raise_error_if(errname != NULL, e_RetrieveError, errname,
287
+ ruby_libvirt_connect_get(d));
288
+
289
+ result = rb_hash_new();
290
+
291
+ if (nparams == 0) {
292
+ return result;
293
+ }
294
+
295
+ params = alloca(typesize * nparams);
296
+
297
+ errname = get_cb(d, flags, params, &nparams, opaque);
298
+ ruby_libvirt_raise_error_if(errname != NULL, e_RetrieveError, errname,
299
+ ruby_libvirt_connect_get(d));
300
+
301
+ for (i = 0; i < nparams; i++) {
302
+ hash_set(params, i, result);
303
+ }
304
+
305
+ return result;
306
+ }
307
+
308
+ VALUE ruby_libvirt_get_typed_parameters(VALUE d, unsigned int flags,
309
+ void *opaque,
310
+ const char *(*nparams_cb)(VALUE d,
311
+ unsigned int flags,
312
+ void *opaque,
313
+ int *nparams),
314
+ const char *(*get_cb)(VALUE d,
315
+ unsigned int flags,
316
+ void *params,
317
+ int *nparams,
318
+ void *opaque))
319
+ {
320
+ return ruby_libvirt_get_parameters(d, flags, opaque,
321
+ sizeof(virTypedParameter), nparams_cb,
322
+ get_cb,
323
+ ruby_libvirt_typed_params_to_hash);
324
+ }
325
+
326
+ void ruby_libvirt_assign_hash_and_flags(VALUE in, VALUE *hash, VALUE *flags)
327
+ {
328
+ if (TYPE(in) == T_HASH) {
329
+ *hash = in;
330
+ *flags = INT2NUM(0);
331
+ }
332
+ else if (TYPE(in) == T_ARRAY) {
333
+ if (RARRAY_LEN(in) != 2) {
334
+ rb_raise(rb_eArgError, "wrong number of arguments (%ld for 1 or 2)",
335
+ RARRAY_LEN(in));
336
+ }
337
+ *hash = rb_ary_entry(in, 0);
338
+ *flags = rb_ary_entry(in, 1);
339
+ }
340
+ else {
341
+ rb_raise(rb_eTypeError, "wrong argument type (expected Hash or Array)");
342
+ }
343
+ }
344
+
345
+ int ruby_libvirt_typed_parameter_assign(VALUE key, VALUE val, VALUE in)
346
+ {
347
+ struct ruby_libvirt_parameter_assign_args *args = (struct ruby_libvirt_parameter_assign_args *)in;
348
+ char *keyname;
349
+ unsigned int i;
350
+ int found;
351
+
352
+ keyname = StringValueCStr(key);
353
+
354
+ found = 0;
355
+ for (i = 0; i < args->num_allowed; i++) {
356
+ if (strcmp(args->allowed[i].name, keyname) == 0) {
357
+ args->params[args->i].type = args->allowed[i].type;
358
+ switch (args->params[args->i].type) {
359
+ case VIR_TYPED_PARAM_INT:
360
+ args->params[i].value.i = NUM2INT(val);
361
+ break;
362
+ case VIR_TYPED_PARAM_UINT:
363
+ args->params[i].value.ui = NUM2UINT(val);
364
+ break;
365
+ case VIR_TYPED_PARAM_LLONG:
366
+ args->params[i].value.l = NUM2LL(val);
367
+ break;
368
+ case VIR_TYPED_PARAM_ULLONG:
369
+ args->params[args->i].value.ul = NUM2ULL(val);
370
+ break;
371
+ case VIR_TYPED_PARAM_DOUBLE:
372
+ args->params[i].value.d = NUM2DBL(val);
373
+ break;
374
+ case VIR_TYPED_PARAM_BOOLEAN:
375
+ args->params[i].value.b = (val == Qtrue) ? 1 : 0;
376
+ break;
377
+ case VIR_TYPED_PARAM_STRING:
378
+ args->params[args->i].value.s = StringValueCStr(val);
379
+ break;
380
+ default:
381
+ rb_raise(rb_eArgError, "Invalid parameter type");
382
+ }
383
+ /* ensure that the field is NULL-terminated */
384
+ args->params[args->i].field[VIR_TYPED_PARAM_FIELD_LENGTH - 1] = '\0';
385
+ strncpy(args->params[args->i].field, keyname,
386
+ VIR_TYPED_PARAM_FIELD_LENGTH - 1);
387
+ (args->i)++;
388
+ found = 1;
389
+ break;
390
+ }
391
+ }
392
+
393
+ if (!found) {
394
+ rb_raise(rb_eArgError, "Unknown key %s", keyname);
395
+ }
396
+
397
+ return ST_CONTINUE;
398
+ }
399
+
400
+ VALUE ruby_libvirt_set_typed_parameters(VALUE d, VALUE input,
401
+ unsigned int flags, void *opaque,
402
+ struct ruby_libvirt_typed_param *allowed,
403
+ unsigned int num_allowed,
404
+ const char *(*set_cb)(VALUE d,
405
+ unsigned int flags,
406
+ virTypedParameterPtr params,
407
+ int nparams,
408
+ void *opaque))
409
+ {
410
+ const char *errname;
411
+ struct ruby_libvirt_parameter_assign_args args;
412
+ unsigned long hashsize;
413
+
414
+ /* make sure input is a hash */
415
+ Check_Type(input, T_HASH);
416
+
417
+ hashsize = RHASH_SIZE(input);
418
+
419
+ if (hashsize == 0) {
420
+ return Qnil;
421
+ }
422
+
423
+ args.allowed = allowed;
424
+ args.num_allowed = num_allowed;
425
+ args.params = alloca(sizeof(virTypedParameter) * hashsize);
426
+ args.i = 0;
427
+
428
+ rb_hash_foreach(input, ruby_libvirt_typed_parameter_assign, (VALUE)&args);
429
+
430
+ errname = set_cb(d, flags, args.params, args.i, opaque);
431
+ ruby_libvirt_raise_error_if(errname != NULL, e_RetrieveError, errname,
432
+ ruby_libvirt_connect_get(d));
433
+
434
+ return Qnil;
435
+ }
436
+
437
+ unsigned int ruby_libvirt_value_to_uint(VALUE in)
438
+ {
439
+ if (NIL_P(in)) {
440
+ return 0;
441
+ }
442
+
443
+ return NUM2UINT(in);
444
+ }
445
+
446
+ int ruby_libvirt_value_to_int(VALUE in)
447
+ {
448
+ if (NIL_P(in)) {
449
+ return 0;
450
+ }
451
+
452
+ return NUM2INT(in);
453
+ }
454
+
455
+ unsigned long ruby_libvirt_value_to_ulong(VALUE in)
456
+ {
457
+ if (NIL_P(in)) {
458
+ return 0;
459
+ }
460
+
461
+ return NUM2ULONG(in);
462
+ }
463
+
464
+ unsigned long long ruby_libvirt_value_to_ulonglong(VALUE in)
465
+ {
466
+ if (NIL_P(in)) {
467
+ return 0;
468
+ }
469
+
470
+ return NUM2ULL(in);
471
+ }
472
+
473
+ int ruby_libvirt_get_maxcpus(virConnectPtr conn)
474
+ {
475
+ int maxcpu = -1;
476
+ virNodeInfo nodeinfo;
477
+
478
+ #if HAVE_VIRNODEGETCPUMAP
479
+ maxcpu = virNodeGetCPUMap(conn, NULL, NULL, 0);
480
+ #endif
481
+ if (maxcpu < 0) {
482
+ /* fall back to nodeinfo */
483
+ ruby_libvirt_raise_error_if(virNodeGetInfo(conn, &nodeinfo) < 0,
484
+ e_RetrieveError, "virNodeGetInfo", conn);
485
+
486
+ maxcpu = VIR_NODEINFO_MAXCPUS(nodeinfo);
487
+ }
488
+
489
+ return maxcpu;
490
+ }