Imported Upstream version 3.3.3
[debian/amanda] / common-src / glib-util.c
1 /*
2  * Copyright (c) 2007-2012 Zmanda, Inc.  All Rights Reserved.
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful, but
10  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
11  * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
12  * for more details.
13  *
14  * You should have received a copy of the GNU General Public License along
15  * with this program; if not, write to the Free Software Foundation, Inc.,
16  * 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
17  *
18  * Contact information: Zmanda Inc., 465 S. Mathilda Ave., Suite 300
19  * Sunnyvale, CA 94085, USA, or: http://www.zmanda.com
20  */
21
22 /*
23  * Utilities that aren't quite included in glib
24  *
25  * Author: Dustin J. Mitchell <dustin@zmanda.com>, Ian Turner <ian@zmanda.com>
26  */
27
28 #include "amanda.h"
29 #include "glib-util.h"
30 #include "conffile.h" /* For find_multiplier. */
31
32 #ifdef HAVE_LIBCURL
33 #include <curl/curl.h>
34
35 #ifdef LIBCURL_USE_OPENSSL
36 #include <openssl/crypto.h>
37 static GMutex **openssl_mutex_array;
38 static void openssl_lock_callback(int mode, int type, const char *file, int line)
39 {
40     (void)file;
41     (void)line;
42     if (mode & CRYPTO_LOCK) {
43         g_mutex_lock(openssl_mutex_array[type]);
44     }
45     else {
46         g_mutex_unlock(openssl_mutex_array[type]);
47     }
48 }
49
50 static void
51 init_ssl(void)
52 {
53     int i;
54
55     openssl_mutex_array = g_new0(GMutex *, CRYPTO_num_locks());
56
57     for (i=0; i<CRYPTO_num_locks(); i++) {
58         openssl_mutex_array[i] = g_mutex_new();
59     }
60     CRYPTO_set_locking_callback(openssl_lock_callback);
61
62 }
63
64 #else /* LIBCURL_USE_OPENSSL */
65 #if defined LIBCURL_USE_GNUTLS
66
67 #include <gcrypt.h>
68 #include <errno.h>
69
70 GCRY_THREAD_OPTION_PTHREAD_IMPL;
71 static void
72 init_ssl(void)
73 {
74   gcry_control(GCRYCTL_SET_THREAD_CBS);
75 }
76
77 #else   /* LIBCURL_USE_GNUTLS  */
78
79 static void
80 init_ssl(void)
81 {
82 }
83 #endif  /* LIBCURL_USE_GNUTLS  */
84 #endif  /* LIBCURL_USE_OPENSSL */
85
86 #else   /* HAVE_LIBCURL */
87 static void
88 init_ssl(void)
89 {
90 }
91 #endif /* HAVE_LIBCURL */
92
93 void
94 glib_init(void) {
95     static gboolean did_glib_init = FALSE;
96     if (did_glib_init) return;
97     did_glib_init = TRUE;
98
99     /* set up libcurl (this must happen before threading 
100      * is initialized) */
101 #ifdef HAVE_LIBCURL
102 # ifdef G_THREADS_ENABLED
103 #  if (GLIB_MAJOR_VERSION < 2 || (GLIB_MAJOR_VERSION == 2 && GLIB_MINOR_VERSION < 31))
104     g_assert(!g_thread_supported()); /* assert threads aren't initialized yet */
105 #  endif
106 # endif
107     g_assert(curl_global_init(CURL_GLOBAL_ALL) == 0);
108 #endif
109
110     /* do a version check */
111 #if GLIB_CHECK_VERSION(2,6,0)
112     {
113         const char *glib_err = glib_check_version(GLIB_MAJOR_VERSION,
114                                                   GLIB_MINOR_VERSION,
115                                                   GLIB_MICRO_VERSION);
116         if (glib_err) {
117             error(_("%s: Amanda was compiled with glib-%d.%d.%d"), glib_err,
118                     GLIB_MAJOR_VERSION, GLIB_MINOR_VERSION, GLIB_MICRO_VERSION);
119             exit(1); /* glib_init may be called before error handling is set up */
120         }
121     }
122 #endif
123
124     /* Initialize glib's type system.  On glib >= 2.24, this will initialize
125      * threads, so it must be done after curl is initialized. */
126     g_type_init();
127
128     /* And set up glib's threads */
129 #if defined(G_THREADS_ENABLED) && !defined(G_THREADS_IMPL_NONE)
130     if (!g_thread_supported())
131         g_thread_init(NULL);
132 #endif
133
134     /* initialize ssl */
135     init_ssl();
136
137 }
138
139 typedef enum {
140     FLAG_STRING_NAME,
141     FLAG_STRING_SHORT_NAME,
142     FLAG_STRING_NICK
143 } FlagString;
144
145 static char ** g_flags_to_strv(int value, GType type, FlagString source);
146
147 void
148 _glib_util_foreach_glue(gpointer data, gpointer func)
149 {
150     void (*one_arg_fn)(gpointer) = (void (*)(gpointer))func;
151     one_arg_fn(data);
152 }
153
154 GValue* g_value_unset_init(GValue* value, GType type) {
155     g_return_val_if_fail(value != NULL, NULL);
156
157     if (G_IS_VALUE(value)) {
158         g_value_unset(value);
159     }
160     g_value_init(value, type);
161     return value;
162 }
163
164 GValue* g_value_unset_copy(const GValue * from, GValue * to) {
165     g_return_val_if_fail(from != NULL, NULL);
166     g_return_val_if_fail(to != NULL, NULL);
167
168     g_value_unset_init(to, G_VALUE_TYPE(from));
169     g_value_copy(from, to);
170     return to;
171 }
172
173 #if (GLIB_MAJOR_VERSION < 2 || (GLIB_MAJOR_VERSION == 2 && GLIB_MINOR_VERSION < 28))
174 void slist_free_full(GSList * list, GDestroyNotify free_fn) {
175     GSList * cur = list;
176
177     while (cur != NULL) {
178         gpointer data = cur->data;
179         free_fn(data);
180         cur = g_slist_next(cur);
181     }
182
183     g_slist_free(list);
184 }
185 #endif
186
187 void g_ptr_array_free_full(GPtrArray * array) {
188     size_t i;
189
190     for (i = 0; i < array->len; i ++) {
191         amfree(g_ptr_array_index(array, i));
192     }
193     g_ptr_array_free(array, TRUE);
194 }
195
196 gboolean g_value_compare(GValue * a, GValue * b) {
197     if (a == NULL && b == NULL)
198         return TRUE;
199     if (a == NULL || b == NULL)
200         return FALSE;
201     if (G_VALUE_TYPE(a) != G_VALUE_TYPE(b))
202         return FALSE;
203     if (g_value_fits_pointer(a) && g_value_fits_pointer(b)) {
204         return g_value_peek_pointer(a) == g_value_peek_pointer(b);
205     } else {
206         /* Since there is no builtin comparison function, we resort to
207            comparing serialized strings. Yuck. */
208         char * a_str;
209         char * b_str;
210         gboolean rval;
211         a_str = g_strdup_value_contents(a);
212         b_str = g_strdup_value_contents(b);
213         rval = (0 == strcmp(a_str, b_str));
214         amfree(a_str);
215         amfree(b_str);
216         return rval;
217     }
218     
219     g_assert_not_reached();
220 }
221
222 static gboolean
223 g_value_set_boolean_from_string(
224     GValue * val,
225     char * str)
226 {
227     int b = string_to_boolean(str);
228
229     if (b == -1)
230         return FALSE;
231
232     g_value_set_boolean(val, b);
233     return TRUE;
234 }
235
236 static gboolean g_value_set_int_from_string(GValue * val, char * string) {
237     long int strto_result;
238     char * strto_end;
239     gint64 multiplier;
240     strto_result = strtol(string, &strto_end, 0);
241     multiplier = find_multiplier(strto_end);
242     if (multiplier == G_MAXINT64) {
243         if (strto_result >= 0) {
244             g_value_set_int(val, G_MAXINT);
245         } else {
246             g_value_set_int(val, G_MININT);
247         }
248         return TRUE;
249     } else if (*string == '\0' || multiplier == 0
250                || strto_result < G_MININT / multiplier
251                || strto_result > G_MAXINT / multiplier) {
252         return FALSE;
253     } else { 
254         g_value_set_int(val, (int)(strto_result * multiplier));
255         return TRUE;
256     }
257 }
258
259 static gboolean g_value_set_uint_from_string(GValue * val, char * string) {
260     unsigned long int strto_result;
261     char * strto_end;
262     guint64 multiplier;
263     strto_result = strtoul(string, &strto_end, 0);
264     multiplier = find_multiplier(strto_end); /* casts */
265     if (multiplier == G_MAXINT64) {
266         g_value_set_uint(val, G_MAXUINT);
267         return TRUE;
268     } else if (multiplier == 0 || *string == '\0' ||
269                strto_result > G_MAXUINT / multiplier) {
270         return FALSE;
271     } else {
272         g_value_set_uint(val, (guint)(strto_result * multiplier));
273         return TRUE;
274     }
275 }
276
277 static gboolean g_value_set_uint64_from_string(GValue * val, char * string) {
278     unsigned long long int strto_result;
279     char * strto_end;
280     guint64 multiplier;
281     strto_result = strtoull(string, &strto_end, 0);
282     multiplier = find_multiplier(strto_end); /* casts */
283     if (multiplier == G_MAXINT64) {
284         g_value_set_uint64(val, G_MAXUINT64);
285         return TRUE;
286     } else if (multiplier == 0 || *string == '\0' ||
287         strto_result > G_MAXUINT64 / multiplier) {
288         return FALSE;
289     } else {
290         g_value_set_uint64(val, (guint64)(strto_result * multiplier));
291         return TRUE;
292     }
293 }
294
295 /* Flags can contain multiple values. We assume here that values are like
296  * C identifiers (that is, they match /[A-Za-z_][A-Za-z0-9_]+/), although
297  * that doesn't seem to be a requirement of GLib. With that assumption in
298  * mind, we look for the format "FLAG_1 | FLAG_2 | ... | FLAG_N". */
299 static gboolean g_value_set_flags_from_string(GValue * val, char * string) {
300     guint value = 0;
301     char * strtok_saveptr;
302     char * string_copy;
303     char * strtok_first_arg;
304     const char delim[] = " \t,|";
305     GFlagsClass * flags_class;
306     
307     flags_class = (GFlagsClass*) g_type_class_ref(G_VALUE_TYPE(val));
308     g_return_val_if_fail(flags_class != NULL, FALSE);
309     g_return_val_if_fail(G_IS_FLAGS_CLASS(flags_class), FALSE);
310
311     /* Don't let strtok stop on original. */
312     strtok_first_arg = string_copy = strdup(string);
313     
314     for (;;) {
315         GFlagsValue * flag_value;
316         char * token = strtok_r(strtok_first_arg, delim, &strtok_saveptr);
317         strtok_first_arg = NULL;
318
319         if (token == NULL) {
320             break;
321         }
322         
323         flag_value = g_flags_get_value_by_name(flags_class, token);
324         if (flag_value == NULL) {
325             flag_value = g_flags_get_value_by_nick(flags_class, token);
326         }
327         if (flag_value == NULL) {
328             g_fprintf(stderr, _("Invalid flag %s for type %s\n"), token,
329                     g_type_name(G_VALUE_TYPE(val)));
330             continue;
331         }
332
333         value |= flag_value->value;
334     }
335     
336     amfree(string_copy);
337     
338     if (value == 0) {
339         g_fprintf(stderr, _("No valid flags for type %s in string %s\n"),
340                 g_type_name(G_VALUE_TYPE(val)), string);
341         return FALSE;
342     }
343     
344     g_value_set_flags(val, value);
345     return TRUE;
346
347 }
348
349 /* This function really ought not to be part of Amanda. In my (Ian's) opinion,
350    serialization and deserialization should be a part of the GValue
351    interface. But it's not, and here we are. */
352 gboolean g_value_set_from_string(GValue * val, char * string) {
353     g_return_val_if_fail(val != NULL, FALSE);
354     g_return_val_if_fail(G_IS_VALUE(val), FALSE);
355
356     if (G_VALUE_HOLDS_BOOLEAN(val)) {
357         return g_value_set_boolean_from_string(val, string);
358     } else if (G_VALUE_HOLDS_INT(val)) {
359         return g_value_set_int_from_string(val, string);
360     } else if (G_VALUE_HOLDS_UINT(val)) {
361         return g_value_set_uint_from_string(val, string);
362     } else if (G_VALUE_HOLDS_UINT64(val)) {
363         return g_value_set_uint64_from_string(val, string);
364     } else if (G_VALUE_HOLDS_STRING(val)) {
365         g_value_set_string(val, string);
366         return TRUE;
367     } else if (G_VALUE_HOLDS_FLAGS(val)) {
368         return g_value_set_flags_from_string(val, string);
369     }
370
371     return TRUE;
372 }
373
374 gint
375 g_compare_strings(
376     gconstpointer a,
377     gconstpointer b)
378 {
379     return strcmp((char *)a, (char *)b);
380 }
381
382 char * g_strjoinv_and_free(char ** strv, const char * seperator) {
383     char * rval = g_strjoinv(seperator, strv);
384     g_strfreev(strv);
385     return rval;
386 }
387
388 char ** g_flags_name_to_strv(int value, GType type) {
389     return g_flags_to_strv(value, type, FLAG_STRING_NAME);
390 }
391
392 char ** g_flags_short_name_to_strv(int value, GType type) {
393     return g_flags_to_strv(value, type, FLAG_STRING_SHORT_NAME);
394 }
395
396 char ** g_flags_nick_to_strv(int value, GType type) {
397     return g_flags_to_strv(value, type, FLAG_STRING_NICK);
398 }
399
400 static char * get_name_from_value(GFlagsValue * value, FlagString source) {
401     switch (source) {
402     case FLAG_STRING_NAME:
403     case FLAG_STRING_SHORT_NAME:
404         return strdup(value->value_name);
405     case FLAG_STRING_NICK:
406         return strdup(value->value_nick);
407     default:
408         return NULL;
409     }
410 }
411
412 /* If freed and notfreed have a common prefix that is different from freed,
413    then return that and free freed. Otherwise, return freed. */
414 static char * find_common_prefix(char * freed, const char * notfreed) {
415     char * freed_ptr = freed;
416     const char * notfreed_ptr = notfreed;
417
418     if (freed == NULL) {
419         if (notfreed == NULL) {
420             return NULL;
421         } else {
422             return strdup(notfreed);
423         }
424     } else if (notfreed == NULL) {
425         amfree(freed);
426         return strdup("");
427     }
428
429     while (*freed_ptr == *notfreed_ptr) {
430         freed_ptr ++;
431         notfreed_ptr ++;
432     }
433
434     *freed_ptr = '\0';
435     return freed;
436 }
437
438 static char ** g_flags_to_strv(int value, GType type,
439                                FlagString source) {
440     GPtrArray * rval;
441     GFlagsValue * flagsvalue;
442     char * common_prefix = NULL;
443     int common_prefix_len;
444     GFlagsClass * class;
445
446     g_return_val_if_fail(G_TYPE_IS_FLAGS(type), NULL);
447     g_return_val_if_fail((class = g_type_class_ref(type)) != NULL, NULL);
448     g_return_val_if_fail(G_IS_FLAGS_CLASS(class), NULL);
449         
450     rval = g_ptr_array_new();
451     for (flagsvalue = class->values;
452          flagsvalue->value_name != NULL;
453          flagsvalue ++) {
454         if (source == FLAG_STRING_SHORT_NAME) {
455             common_prefix = find_common_prefix(common_prefix,
456                                                flagsvalue->value_name);
457         }
458                                                
459         if ((flagsvalue->value == 0 && value == 0) ||
460             (flagsvalue->value != 0 && (value & flagsvalue->value))) {
461             g_ptr_array_add(rval, get_name_from_value(flagsvalue, source));
462         }
463     }
464
465     if (source == FLAG_STRING_SHORT_NAME && common_prefix != NULL &&
466         ((common_prefix_len = strlen(common_prefix))) > 0) {
467         char * old;
468         char * new;
469         guint i;
470         for (i = 0; i < rval->len; i ++) {
471             old = g_ptr_array_index(rval, i);
472             new = strdup(old + common_prefix_len);
473             g_ptr_array_index(rval, i) = new;
474             g_free(old);
475         }
476     }
477     
478     g_ptr_array_add(rval, NULL);
479
480     amfree(common_prefix);
481     return (char**)g_ptr_array_free(rval, FALSE);
482 }
483
484 char * g_english_strjoinv(char ** strv, const char * conjunction) {
485     int length;
486     char * last;
487     char * joined;
488     char * rval;
489     strv = g_strdupv(strv);
490
491     length = g_strv_length(strv);
492
493     if (length == 1)
494         return stralloc(strv[0]);
495
496     last = strv[length - 1];
497     strv[length - 1] = NULL;
498     
499     joined = g_strjoinv(", ", strv);
500     rval = g_strdup_printf("%s, %s %s", joined, conjunction, last);
501
502     g_free(joined);
503     g_free(last);
504     g_strfreev(strv);
505     return rval;
506 }
507
508 char * g_english_strjoinv_and_free(char ** strv, const char * conjunction) {
509     char * rval = g_english_strjoinv(strv, conjunction);
510     g_strfreev(strv);
511     return rval;   
512 }
513
514 #if !(GLIB_CHECK_VERSION(2,6,0))
515 guint g_strv_length(gchar ** strv) {
516     int rval = 0;
517
518     if (G_UNLIKELY(strv == NULL))
519         return 0;
520
521     while (*strv != NULL) {
522         rval ++;
523         strv ++;
524     }
525     return rval;
526 }
527 #endif /* GLIB_CHECK_VERSION(2.6.0) */
528
529 #if !GLIB_CHECK_VERSION(2,4,0)
530 void
531 g_ptr_array_foreach (GPtrArray *array,
532                      GFunc      func,
533                      gpointer   user_data)
534 {
535   guint i;
536
537   g_return_if_fail (array);
538
539   for (i = 0; i < array->len; i++)
540     (*func) (array->pdata[i], user_data);
541 }
542 #endif
543
544 guint
545 g_str_amanda_hash(
546         gconstpointer key)
547 {
548     /* modified version of glib's hash function, copyright
549      * GLib Team and others 1997-2000. */
550     const char *p;
551     guint h = 0;
552
553     for (p = key; *p != '\0'; p++)
554         h = (h << 5) - h + (('_' == *p) ? '-' : g_ascii_tolower(*p));
555
556     return h;
557 }
558
559 gboolean
560 g_str_amanda_equal(
561         gconstpointer v1,
562         gconstpointer v2)
563 {
564     const gchar *p1 = v1, *p2 = v2;
565     while (*p1) {
566         /* letting '-' == '_' */
567         if (!('-' == *p1 || '_' == *p1) || !('-' == *p2 || '_' == *p2))
568             if (g_ascii_tolower(*p1) != g_ascii_tolower(*p2))
569                 return FALSE;
570
571         p1++;
572         p2++;
573     }
574
575     /* p1 is at '\0' is p2 too? */
576     return *p2? FALSE : TRUE;
577 }