1 /* Copyright (C) 2016-2020 Greenbone Networks GmbH
2  *
3  * SPDX-License-Identifier: AGPL-3.0-or-later
4  *
5  * This program is free software: you can redistribute it and/or modify
6  * it under the terms of the GNU Affero General Public License as
7  * published by the Free Software Foundation, either version 3 of the
8  * License, or (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU Affero General Public License for more details.
14  *
15  * You should have received a copy of the GNU Affero General Public License
16  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
17  */
18 
19 /**
20  * @file utils.c
21  * @brief Generic utilities
22  *
23  * Generic helper utilities.  None of these are GVM specific.  They could
24  * be used anywhere.
25  */
26 
27 /**
28  * @brief Enable extra functions.
29  *
30  * time.h in glibc2 needs this for strptime.
31  */
32 #define _XOPEN_SOURCE
33 
34 /**
35  * @brief Needed for nanosleep.
36  */
37 //#define _POSIX_C_SOURCE 199309L
38 
39 #include "utils.h"
40 
41 #include <assert.h>
42 #include <ctype.h>
43 #include <errno.h>
44 #include <fcntl.h>
45 #include <stdlib.h>
46 #include <string.h>
47 #include <sys/file.h>
48 #include <sys/types.h>
49 #include <sys/stat.h>
50 #include <unistd.h>
51 
52 #undef G_LOG_DOMAIN
53 /**
54  * @brief GLib log domain.
55  */
56 #define G_LOG_DOMAIN "md manage"
57 
58 
59 /* Sleep. */
60 
61 /**
62  * @brief Sleep for some number of microseconds, handling interrupts.
63  *
64  * @param[in] microseconds  Number of microseconds.
65  *
66  * @return 0 success, -1 error (with errno set).
67  */
68 int
gvm_usleep(unsigned int microseconds)69 gvm_usleep (unsigned int microseconds)
70 {
71   struct timespec a, b, *requested, *remaining;
72   int ret;
73 
74   requested = &a;
75   remaining = &b;
76 
77   requested->tv_sec = microseconds / 1000000;
78   requested->tv_nsec = (microseconds % 1000000) * 1000;
79 
80   while ((ret = nanosleep (requested, remaining)) && (errno == EINTR))
81     {
82       struct timespec *temp;
83       temp = requested;
84       requested = remaining;
85       remaining = temp;
86     }
87   if (ret)
88     return -1;
89   return 0;
90 }
91 
92 /**
93  * @brief Sleep for some number of seconds, handling interrupts.
94  *
95  * @param[in] seconds  Number of seconds.
96  *
97  * @return 0 success, -1 error (with errno set).
98  */
99 int
gvm_sleep(unsigned int seconds)100 gvm_sleep (unsigned int seconds)
101 {
102   return gvm_usleep (seconds * 1000000);
103 }
104 
105 
106 /* Time. */
107 
108 /**
109  * @brief Convert a UTC time into seconds since epoch.
110  *
111  * @param[in]  format     Format of time.
112  * @param[in]  text_time  Time as text.
113  *
114  * @return Time since epoch.  0 on error.
115  */
116 static int
parse_utc_time(const char * format,const char * text_time)117 parse_utc_time (const char *format, const char *text_time)
118 {
119   int epoch_time;
120   struct tm tm;
121   gchar *tz;
122 
123   /* Scanner sends UTC in ctime format: "Wed Jun 30 21:49:08 1993". */
124 
125   /* Store current TZ. */
126   tz = getenv ("TZ") ? g_strdup (getenv ("TZ")) : NULL;
127 
128   if (setenv ("TZ", "UTC", 1) == -1)
129     {
130       g_warning ("%s: Failed to switch to UTC", __func__);
131       if (tz != NULL)
132         setenv ("TZ", tz, 1);
133       g_free (tz);
134       return 0;
135     }
136 
137   memset (&tm, 0, sizeof (struct tm));
138   if (strptime ((char*) text_time, format, &tm) == NULL)
139     {
140       g_warning ("%s: Failed to parse time", __func__);
141       if (tz != NULL)
142         setenv ("TZ", tz, 1);
143       g_free (tz);
144       return 0;
145     }
146   epoch_time = mktime (&tm);
147   if (epoch_time == -1)
148     {
149       g_warning ("%s: Failed to make time", __func__);
150       if (tz != NULL)
151         setenv ("TZ", tz, 1);
152       g_free (tz);
153       return 0;
154     }
155 
156   /* Revert to stored TZ. */
157   if (tz)
158     {
159       if (setenv ("TZ", tz, 1) == -1)
160         {
161           g_warning ("%s: Failed to switch to original TZ", __func__);
162           g_free (tz);
163           return 0;
164         }
165     }
166   else
167     unsetenv ("TZ");
168 
169   g_free (tz);
170   return epoch_time;
171 }
172 
173 /**
174  * @brief Parses a time string using strptime, resetting the data structure.
175  *
176  * @param[in]  text_time  The time string to parse.
177  * @param[in]  format     The format string.
178  * @param[out] tm         The tm date structure to write to.
179  *
180  * @return Pointer to first character not processed by strptime.
181  */
182 static char *
strptime_with_reset(const char * text_time,const char * format,struct tm * tm)183 strptime_with_reset (const char *text_time, const char *format, struct tm* tm)
184 {
185   memset (tm, 0, sizeof (struct tm));
186   tm->tm_isdst = -1;
187   return strptime ((char*) text_time, format, tm);
188 }
189 
190 /**
191  * @brief Converts a tm struct into seconds since epoch with a given timezone.
192  *
193  * @param[in]  tm       The time data structure.
194  * @param[in]  new_tz   The timezone to use or NULL for UTC.
195  *
196  * @return The seconds since epoch from the given time data.
197  */
198 static time_t
mktime_with_tz(struct tm * tm,const char * new_tz)199 mktime_with_tz (struct tm *tm, const char *new_tz)
200 {
201   gchar *tz;
202   int epoch_time;
203 
204   /* Store current TZ. */
205   tz = getenv ("TZ") ? g_strdup (getenv ("TZ")) : NULL;
206 
207   /* Set new TZ */
208   if (setenv ("TZ",
209               new_tz
210                 ? new_tz
211                 : "UTC",
212               1)
213       == -1)
214     {
215       g_warning ("%s: Failed to switch to timezone %s",
216                  __func__, new_tz);
217       if (tz != NULL)
218         setenv ("TZ", tz, 1);
219       g_free (tz);
220       return 0;
221     }
222 
223   /* Get the time */
224   epoch_time = mktime (tm);
225 
226   /* Revert to stored TZ. */
227   if (tz)
228     {
229       if (setenv ("TZ", tz, 1) == -1)
230         {
231           g_warning ("%s: Failed to switch to original TZ", __func__);
232           g_free (tz);
233           return 0;
234         }
235     }
236   else
237     unsetenv ("TZ");
238 
239   return epoch_time;
240 }
241 
242 /**
243  * @brief Convert a UTC ctime string into seconds since the epoch.
244  *
245  * @param[in]  text_time  Time as text in ctime format.
246  *
247  * @return Time since epoch.  0 on error.
248  */
249 int
parse_utc_ctime(const char * text_time)250 parse_utc_ctime (const char *text_time)
251 {
252   return parse_utc_time ("%a %b %d %H:%M:%S %Y", text_time);
253 }
254 
255 /**
256  * @brief Convert a feed timestamp into seconds since epoch.
257  *
258  * @param[in]  text_time  Time as text in ctime format.
259  *
260  * @return Time since epoch.  0 on error.
261  */
262 int
parse_feed_timestamp(const char * text_time)263 parse_feed_timestamp (const char *text_time)
264 {
265   return parse_utc_time ("%Y%m%d", text_time);
266 }
267 
268 /**
269  * @brief Convert a ctime into seconds since epoch.
270  *
271  * Use the current timezone.
272  *
273  * @param[in]  text_time  Time as text in ctime format.
274  *
275  * @return Time since epoch.
276  */
277 int
parse_ctime(const char * text_time)278 parse_ctime (const char *text_time)
279 {
280   int epoch_time;
281   struct tm tm;
282 
283   /* ctime format: "Wed Jun 30 21:49:08 1993". */
284 
285   memset (&tm, 0, sizeof (struct tm));
286   if (strptime ((char*) text_time, "%a %b %d %H:%M:%S %Y", &tm) == NULL)
287     {
288       g_warning ("%s: Failed to parse time '%s'", __func__, text_time);
289       return 0;
290     }
291   epoch_time = mktime (&tm);
292   if (epoch_time == -1)
293     {
294       g_warning ("%s: Failed to make time '%s'", __func__, text_time);
295       return 0;
296     }
297 
298   return epoch_time;
299 }
300 
301 /**
302  * @brief Calculate difference between now and epoch_time in days
303  *
304  * @param[in]  epoch_time  Time in seconds from epoch.
305  *
306  * @return Int days bettween now and epoch_time or -1 if epoch_time is in the
307  * past
308  */
309 int
days_from_now(time_t * epoch_time)310 days_from_now (time_t *epoch_time)
311 {
312   time_t now = time (NULL);
313   int diff = *epoch_time - now;
314 
315   if (diff < 0) return -1;
316   return diff / 86400; /* 60 sec * 60 min * 24 h */
317 }
318 
319 /**
320  * @brief Convert an ISO time into seconds since epoch.
321  *
322  * If no offset is specified, the given timezone is used (UTC in case of NULL).
323  *
324  * @param[in]  text_time  Time as text in ISO format: 2011-11-03T09:23:28+02:00.
325  * @param[in]  fallback_tz  The fallback timezone if offset is missing.
326  *
327  * @return Time since epoch.  0 on error.
328  */
329 time_t
parse_iso_time_tz(const char * text_time,const char * fallback_tz)330 parse_iso_time_tz (const char *text_time, const char *fallback_tz)
331 {
332   static GRegex *regex = NULL;
333   GMatchInfo *match_info;
334   struct tm tm;
335   int epoch_time;
336 
337   epoch_time = 0;
338 
339   if (regex == NULL)
340     regex = g_regex_new ("^([0-9]{4}-[0-9]{2}-[0-9]{2})"
341                          "[T ]([0-9]{2}:[0-9]{2})"
342                          "(:[0-9]{2})?(?:\\.[0-9]+)?"
343                          "(Z|[+-][0-9]{2}:?[0-9]{2})?$",
344                          0, 0, NULL);
345 
346   if (g_regex_match (regex, text_time, 0, &match_info))
347     {
348       gchar *date_str, *time_str, *secs_str, *offset_str, *cleaned_text_time;
349 
350       /* Converting the date-time string to a more strictly defined format
351        *  makes it easier to parse variants of the ISO time:
352        * - Using a space to separate the date and time instead of "T"
353        * - Omitting the seconds
354        * - Having fractional seconds
355        */
356       date_str = g_match_info_fetch (match_info, 1);
357       time_str = g_match_info_fetch (match_info, 2);
358       secs_str = g_match_info_fetch (match_info, 3);
359       offset_str = g_match_info_fetch (match_info, 4);
360       cleaned_text_time
361         = g_strdup_printf ("%sT%s%s%s",
362                            date_str ? date_str : "",
363                            time_str ? time_str : "",
364                            secs_str && strcmp (secs_str, "")
365                             ? secs_str : ":00",
366                            offset_str ? offset_str : "");
367       #if !defined(__GLIBC__)
368         if (strptime_with_reset ((char*) cleaned_text_time, "%Y-%m-%dT%T", &tm))
369       #else
370         if (strptime_with_reset ((char*) cleaned_text_time, "%FT%T%z", &tm))
371       #endif
372         {
373           /* ISO time with numeric offset (e.g. 2020-06-01T01:02:03+04:30) */
374           tm.tm_sec = tm.tm_sec - tm.tm_gmtoff;
375           tm.tm_gmtoff = 0;
376           epoch_time = mktime_with_tz (&tm, "UTC");
377         }
378       #if !defined(__GLIBC__)
379         else if (strptime_with_reset ((char*) cleaned_text_time, "%Y-%m-%dT%T", &tm))
380       #else
381         else if (strptime_with_reset ((char*) cleaned_text_time, "%FT%TZ", &tm))
382       #endif
383         {
384           /* ISO time with "Z" for UTC timezone (e.g. 2020-06-01T01:02:03Z) */
385           epoch_time = mktime_with_tz (&tm, "UTC");
386         }
387       #if !defined(__GLIBC__)
388         else if (strptime_with_reset ((char*) cleaned_text_time, "%Y-%m-%dT%T", &tm))
389       #else
390         else if (strptime_with_reset ((char*) cleaned_text_time, "%FT%T", &tm))
391       #endif
392         {
393           /* ISO time without timezone suffix (e.g. 2020-06-01T01:02:03) */
394           epoch_time = mktime_with_tz (&tm, fallback_tz ? fallback_tz : "UTC");
395         }
396       else
397         g_warning ("%s: Could not parse time %s", __func__, text_time);
398 
399       g_free (date_str);
400       g_free (time_str);
401       g_free (secs_str);
402       g_free (offset_str);
403       g_free (cleaned_text_time);
404     }
405   else
406     g_warning ("%s: Could not parse time %s", __func__, text_time);
407 
408   g_match_info_free (match_info);
409 
410   if (epoch_time == -1)
411     {
412       g_warning ("%s: mktime failed for time %s", __func__, text_time);
413       return 0;
414     }
415 
416   return epoch_time;
417 }
418 
419 /**
420  * @brief Create an ISO time from seconds since epoch.
421  *
422  * @param[in]  epoch_time  Time in seconds from epoch.
423  * @param[out] abbrev      Abbreviation for current timezone.
424  *
425  * @return Pointer to ISO time in static memory, or NULL on error.
426  */
427 static char *
iso_time_internal(time_t * epoch_time,const char ** abbrev)428 iso_time_internal (time_t *epoch_time, const char **abbrev)
429 {
430   struct tm tm;
431   static char time_string[100];
432 
433   if (localtime_r (epoch_time, &tm) == NULL)
434     return NULL;
435 #if defined(__FreeBSD__) || defined(__DragonFly__)
436   if (tm.tm_gmtoff == 0)
437 #else
438   if (timezone == 0)
439 #endif
440     {
441       #if !defined(__GLIBC__)
442         if (strftime (time_string, 98, "%Y-%m-%dT%T", &tm) == 0)
443       #else
444         if (strftime (time_string, 98, "%FT%TZ", &tm) == 0)
445       #endif
446         return NULL;
447 
448       if (abbrev)
449         *abbrev = "UTC";
450     }
451   else
452     {
453       int len;
454 
455       #if !defined(__GLIBC__)
456         if (strftime (time_string, 98, "%Y-%m-%dT%T", &tm) == 0)
457       #else
458         if (strftime (time_string, 98, "%FT%T%z", &tm) == 0)
459       #endif
460         return NULL;
461 
462       /* Insert the ISO 8601 colon by hand. */
463       len = strlen (time_string);
464       time_string[len + 1] = '\0';
465       time_string[len] = time_string[len - 1];
466       time_string[len - 1] = time_string[len - 2];
467       time_string[len - 2] = ':';
468 
469       if (abbrev)
470         {
471           static char abbrev_string[100];
472           if (strftime (abbrev_string, 98, "%Z", &tm) == 0)
473             return NULL;
474           *abbrev = abbrev_string;
475         }
476     }
477 
478   return time_string;
479 }
480 
481 /**
482  * @brief Create an ISO time from seconds since epoch.
483  *
484  * @param[in]  epoch_time  Time in seconds from epoch.
485  *
486  * @return Pointer to ISO time in static memory, or NULL on error.
487  */
488 char *
iso_time(time_t * epoch_time)489 iso_time (time_t *epoch_time)
490 {
491   return iso_time_internal (epoch_time, NULL);
492 }
493 
494 /**
495  * @brief Create an ISO time from seconds since epoch, given a timezone.
496  *
497  * @param[in]  epoch_time  Time in seconds from epoch.
498  * @param[in]  zone        Timezone.
499  * @param[out] abbrev      Timezone abbreviation.
500  *
501  * @return Pointer to ISO time in static memory, or NULL on error.
502  */
503 char *
iso_time_tz(time_t * epoch_time,const char * zone,const char ** abbrev)504 iso_time_tz (time_t *epoch_time, const char *zone, const char **abbrev)
505 {
506   gchar *tz;
507   char *ret;
508 
509   if (zone == NULL)
510     return iso_time (epoch_time);
511 
512   /* Store current TZ. */
513   tz = getenv ("TZ") ? g_strdup (getenv ("TZ")) : NULL;
514 
515   if (setenv ("TZ", zone, 1) == -1)
516     {
517       g_warning ("%s: Failed to switch to zone", __func__);
518       if (tz != NULL)
519         setenv ("TZ", tz, 1);
520       g_free (tz);
521       return iso_time (epoch_time);
522     }
523 
524   tzset ();
525   ret = iso_time_internal (epoch_time, abbrev);
526 
527   /* Revert to stored TZ. */
528   if (tz)
529     {
530       if (setenv ("TZ", tz, 1) == -1)
531         {
532           g_warning ("%s: Failed to switch to original TZ", __func__);
533           g_free (tz);
534           return ret;
535         }
536     }
537   else
538     unsetenv ("TZ");
539 
540   g_free (tz);
541   return ret;
542 }
543 
544 
545 /* Locks. */
546 
547 /**
548  * @brief Lock a file.
549  *
550  * @param[in]  lockfile           Lockfile.
551  * @param[in]  lockfile_name      Basename or full path of lock file.
552  * @param[in]  operation          LOCK_EX (exclusive) or LOCK_SH (shared).
553  *                                Maybe ORd with LOCK_NB to prevent blocking.
554  * @param[in]  name_is_full_path  Whether the name is a full path.
555  *
556  * @return 0 success, 1 already locked, -1 error
557  */
558 static int
lock_internal(lockfile_t * lockfile,const gchar * lockfile_name,int operation,gboolean name_is_full_path)559 lock_internal (lockfile_t *lockfile, const gchar *lockfile_name,
560                int operation, gboolean name_is_full_path)
561 {
562   mode_t old_umask;
563   int fd;
564   gchar *full_name;
565 
566   /* Open the lock file. */
567 
568   if (name_is_full_path)
569     full_name = g_strdup (lockfile_name);
570   else
571     full_name = g_build_filename (GVM_RUN_DIR, lockfile_name, NULL);
572 
573   old_umask = umask (0);
574   fd = open (full_name, O_RDWR | O_CREAT,
575              /* "-rw-rw-r--" */
576              S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH);
577   if (fd == -1)
578     {
579       g_warning ("Failed to open lock file '%s': %s", full_name,
580                  strerror (errno));
581       umask (old_umask);
582       lockfile->name = NULL;
583       g_free (full_name);
584       return -1;
585     }
586   umask (old_umask);
587 
588   /* Lock the lockfile. */
589 
590   if (flock (fd, operation))  /* Blocks, unless operation includes LOCK_NB. */
591     {
592       int flock_errno;
593 
594       flock_errno = errno;
595       lockfile->name = NULL;
596       g_free (full_name);
597       if (close (fd))
598         g_warning ("%s: failed to close lock file fd: %s",
599                    __func__,
600                    strerror (errno));
601       if (flock_errno == EWOULDBLOCK)
602         return 1;
603       g_warning ("%s: flock: %s", __func__, strerror (flock_errno));
604       return -1;
605     }
606 
607   lockfile->fd = fd;
608   lockfile->name = full_name;
609 
610   return 0;
611 }
612 
613 /**
614  * @brief Lock a file exclusively.
615  *
616  * Block until file is locked.
617  *
618  * @param[in]  lockfile           Lockfile.
619  * @param[in]  lockfile_basename  Basename of lock file.
620  *
621  * @return 0 success, 1 already locked, -1 error
622  */
623 int
lockfile_lock(lockfile_t * lockfile,const gchar * lockfile_basename)624 lockfile_lock (lockfile_t *lockfile, const gchar *lockfile_basename)
625 {
626   g_debug ("%s: lock '%s'", __func__, lockfile_basename);
627   return lock_internal (lockfile, lockfile_basename, LOCK_EX, FALSE);
628 }
629 
630 /**
631  * @brief Lock a file exclusively, without blocking.
632  *
633  * @param[in]  lockfile           Lockfile.
634  * @param[in]  lockfile_basename  Basename of lock file.
635  *
636  * @return 0 success, 1 already locked, -1 error
637  */
638 int
lockfile_lock_nb(lockfile_t * lockfile,const gchar * lockfile_basename)639 lockfile_lock_nb (lockfile_t *lockfile, const gchar *lockfile_basename)
640 {
641   g_debug ("%s: lock '%s'", __func__, lockfile_basename);
642   return lock_internal (lockfile, lockfile_basename, LOCK_EX | LOCK_NB, FALSE);
643 }
644 
645 /**
646  * @brief Lock a file exclusively, without blocking, given a full path.
647  *
648  * @param[in]  lockfile       Lockfile.
649  * @param[in]  lockfile_path  Full path of lock file.
650  *
651  * @return 0 success, 1 already locked, -1 error
652  */
653 int
lockfile_lock_path_nb(lockfile_t * lockfile,const gchar * lockfile_path)654 lockfile_lock_path_nb (lockfile_t *lockfile, const gchar *lockfile_path)
655 {
656   g_debug ("%s: lock '%s'", __func__, lockfile_path);
657   return lock_internal (lockfile, lockfile_path, LOCK_EX | LOCK_NB, TRUE);
658 }
659 
660 /**
661  * @brief Lock a file with a shared lock.
662  *
663  * @param[in]  lockfile           Lockfile.
664  * @param[in]  lockfile_basename  Basename of lock file.
665  *
666  * @return 0 success, 1 already locked, -1 error
667  */
668 int
lockfile_lock_shared_nb(lockfile_t * lockfile,const gchar * lockfile_basename)669 lockfile_lock_shared_nb (lockfile_t *lockfile, const gchar *lockfile_basename)
670 {
671   g_debug ("%s: lock '%s'", __func__, lockfile_basename);
672   return lock_internal (lockfile, lockfile_basename, LOCK_SH | LOCK_NB, FALSE);
673 }
674 
675 /**
676  * @brief Unlock a file.
677  *
678  * @param[in]  lockfile  Lockfile.
679  *
680  * @return 0 success, -1 error
681  */
682 int
lockfile_unlock(lockfile_t * lockfile)683 lockfile_unlock (lockfile_t *lockfile)
684 {
685   if (lockfile->name == NULL)
686     return 0;
687 
688   assert (lockfile->fd);
689 
690   g_debug ("%s: unlock '%s'", __func__, lockfile->name);
691 
692   /* Close the lock file. */
693 
694   if (close (lockfile->fd))
695     {
696       g_free (lockfile->name);
697       lockfile->name = NULL;
698       g_warning ("Failed to close lock file: %s", strerror (errno));
699       return -1;
700     }
701 
702   /* Clear the lock file data. */
703 
704   g_free (lockfile->name);
705   lockfile->name = NULL;
706 
707   return 0;
708 }
709 
710 /**
711  * @brief Check if a file is locked.
712  *
713  * @param[in]  lockfile_basename  Basename of lock file.
714  *
715  * @return 0 free, 1 locked, -1 error
716  */
717 int
lockfile_locked(const gchar * lockfile_basename)718 lockfile_locked (const gchar *lockfile_basename)
719 {
720   int ret;
721   lockfile_t lockfile;
722 
723   g_debug ("%s: check '%s'", __func__, lockfile_basename);
724 
725   ret = lockfile_lock_nb (&lockfile, lockfile_basename);
726   if ((ret == 0) && lockfile_unlock (&lockfile))
727     return -1;
728   return ret;
729 }
730 
731 
732 /* UUIDs. */
733 
734 /**
735  * @brief Check whether a string is a UUID.
736  *
737  * @param[in]  uuid  Potential UUID.
738  *
739  * @return 1 yes, 0 no.
740  */
741 int
is_uuid(const char * uuid)742 is_uuid (const char *uuid)
743 {
744   while (*uuid) if (isxdigit (*uuid) || (*uuid == '-')) uuid++; else return 0;
745   return 1;
746 }
747 
748 
749 /* XML. */
750 
751 /**
752  * @brief Create entity from XML file.
753  *
754  * @param[in]  path    Path to XML.
755  * @param[out] config  Config tree.
756  *
757  * @return 0 success, -1 error.
758  */
759 int
parse_xml_file(const gchar * path,entity_t * config)760 parse_xml_file (const gchar *path, entity_t *config)
761 {
762   gsize xml_len;
763   char *xml;
764   GError *error;
765 
766   /* Buffer the file. */
767 
768   error = NULL;
769   g_file_get_contents (path,
770                        &xml,
771                        &xml_len,
772                        &error);
773   if (error)
774     {
775       g_warning ("%s: Failed to read file: %s",
776                   __func__,
777                   error->message);
778       g_error_free (error);
779       return -1;
780     }
781 
782   /* Parse the buffer into an entity. */
783 
784   if (parse_entity (xml, config))
785     {
786       g_free (xml);
787       g_warning ("%s: Failed to parse XML", __func__);
788       return -1;
789     }
790   g_free (xml);
791 
792   return 0;
793 }
794 
795 
796 /* Signals. */
797 
798 /**
799  * @brief Setup signal handler.
800  *
801  * Exit on failure.
802  *
803  * @param[in]  signal   Signal.
804  * @param[in]  handler  Handler.
805  * @param[in]  block    Whether to block all other signals during handler.
806  */
807 void
setup_signal_handler(int signal,void (* handler)(int),int block)808 setup_signal_handler (int signal, void (*handler) (int), int block)
809 {
810   struct sigaction action;
811 
812   memset (&action, '\0', sizeof (action));
813   if (block)
814     sigfillset (&action.sa_mask);
815   else
816     sigemptyset (&action.sa_mask);
817   action.sa_handler = handler;
818   if (sigaction (signal, &action, NULL) == -1)
819     {
820       g_critical ("%s: failed to register %s handler",
821                   __func__, strsignal (signal));
822       exit (EXIT_FAILURE);
823     }
824 }
825 
826 /**
827  * @brief Setup signal handler.
828  *
829  * Exit on failure.
830  *
831  * @param[in]  signal   Signal.
832  * @param[in]  handler  Handler.
833  * @param[in]  block    Whether to block all other signals during handler.
834  */
835 void
setup_signal_handler_info(int signal,void (* handler)(int,siginfo_t *,void *),int block)836 setup_signal_handler_info (int signal,
837                            void (*handler) (int, siginfo_t *, void *),
838                            int block)
839 {
840   struct sigaction action;
841 
842   memset (&action, '\0', sizeof (action));
843   if (block)
844     sigfillset (&action.sa_mask);
845   else
846     sigemptyset (&action.sa_mask);
847   action.sa_flags |= SA_SIGINFO;
848   action.sa_sigaction = handler;
849   if (sigaction (signal, &action, NULL) == -1)
850     {
851       g_critical ("%s: failed to register %s handler",
852                   __func__, strsignal (signal));
853       exit (EXIT_FAILURE);
854     }
855 }
856 
857 
858 /* Forking. */
859 
860 /**
861  * @brief Fork, setting default handlers for TERM, INT and QUIT in child.
862  *
863  * This should be used for pretty much all processes forked directly from
864  * the main gvmd process, because the main process's signal handlers will
865  * not longer work, because the child does not use the pselect loop.
866  *
867  * @return PID from fork.
868  */
869 int
fork_with_handlers()870 fork_with_handlers ()
871 {
872   pid_t pid;
873 
874   pid = fork ();
875   if (pid == 0)
876     {
877       setup_signal_handler (SIGTERM, SIG_DFL, 0);
878       setup_signal_handler (SIGINT, SIG_DFL, 0);
879       setup_signal_handler (SIGQUIT, SIG_DFL, 0);
880     }
881   return pid;
882 }
883