shared: move NM_UTILS_ERROR to shared-utils
[NetworkManager.git] / src / nm-core-utils.c
1 /* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
2 /* NetworkManager -- Network link manager
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License 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  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17  *
18  * Copyright 2004 - 2014 Red Hat, Inc.
19  * Copyright 2005 - 2008 Novell, Inc.
20  */
21
22 #include "nm-default.h"
23
24 #include "nm-core-utils.h"
25
26 #include <errno.h>
27 #include <fcntl.h>
28 #include <string.h>
29 #include <unistd.h>
30 #include <stdlib.h>
31 #include <resolv.h>
32 #include <sys/types.h>
33 #include <sys/wait.h>
34 #include <sys/stat.h>
35 #include <linux/if.h>
36 #include <linux/if_infiniband.h>
37 #include <net/ethernet.h>
38
39 #include "nm-utils.h"
40 #include "nm-core-internal.h"
41 #include "nm-setting-connection.h"
42 #include "nm-setting-ip4-config.h"
43 #include "nm-setting-ip6-config.h"
44 #include "nm-setting-wireless.h"
45 #include "nm-setting-wireless-security.h"
46
47 /*
48  * Some toolchains (E.G. uClibc 0.9.33 and earlier) don't export
49  * CLOCK_BOOTTIME even though the kernel supports it, so provide a
50  * local definition
51  */
52 #ifndef CLOCK_BOOTTIME
53 #define CLOCK_BOOTTIME 7
54 #endif
55
56 G_STATIC_ASSERT (sizeof (NMUtilsTestFlags) <= sizeof (int));
57 int _nm_utils_testing = 0;
58
59 gboolean
60 nm_utils_get_testing_initialized ()
61 {
62         NMUtilsTestFlags flags;
63
64         flags = (NMUtilsTestFlags) _nm_utils_testing;
65         if (flags == NM_UTILS_TEST_NONE)
66                 flags = (NMUtilsTestFlags) g_atomic_int_get (&_nm_utils_testing);
67         return flags != NM_UTILS_TEST_NONE;
68 }
69
70 NMUtilsTestFlags
71 nm_utils_get_testing ()
72 {
73         NMUtilsTestFlags flags;
74
75         flags = (NMUtilsTestFlags) _nm_utils_testing;
76         if (flags != NM_UTILS_TEST_NONE) {
77                 /* Flags already initialized. Return them. */
78                 return flags & NM_UTILS_TEST_ALL;
79         }
80
81         /* Accessing nm_utils_get_testing() causes us to set the flags to initialized.
82          * Detecting running tests also based on g_test_initialized(). */
83         flags = _NM_UTILS_TEST_INITIALIZED;
84         if (g_test_initialized ())
85                 flags |= _NM_UTILS_TEST_GENERAL;
86
87         if (g_atomic_int_compare_and_exchange (&_nm_utils_testing, 0, (int) flags)) {
88                 /* Done. We set it. */
89                 return flags & NM_UTILS_TEST_ALL;
90         }
91         /* It changed in the meantime (??). Re-read the value. */
92         return ((NMUtilsTestFlags) _nm_utils_testing) & NM_UTILS_TEST_ALL;
93 }
94
95 void
96 _nm_utils_set_testing (NMUtilsTestFlags flags)
97 {
98         g_assert (!NM_FLAGS_ANY (flags, ~NM_UTILS_TEST_ALL));
99
100         /* mask out everything except ALL, and always set GENERAL. */
101         flags = (flags & NM_UTILS_TEST_ALL) | (_NM_UTILS_TEST_GENERAL | _NM_UTILS_TEST_INITIALIZED);
102
103         if (!g_atomic_int_compare_and_exchange (&_nm_utils_testing, 0, (int) flags)) {
104                 /* We only allow setting _nm_utils_set_testing() once, before fetching the
105                  * value with nm_utils_get_testing(). */
106                 g_return_if_reached ();
107         }
108 }
109
110 /*****************************************************************************/
111
112 static GSList *_singletons = NULL;
113 static gboolean _singletons_shutdown = FALSE;
114
115 static void
116 _nm_singleton_instance_weak_cb (gpointer data,
117                                 GObject *where_the_object_was)
118 {
119         _singletons = g_slist_remove (_singletons, where_the_object_was);
120 }
121
122 static void __attribute__((destructor))
123 _nm_singleton_instance_destroy (void)
124 {
125         _singletons_shutdown = TRUE;
126
127         while (_singletons) {
128                 GObject *instance = _singletons->data;
129
130                 _singletons = g_slist_delete_link (_singletons, _singletons);
131
132                 g_object_weak_unref (instance, _nm_singleton_instance_weak_cb, NULL);
133
134                 if (instance->ref_count > 1)
135                         nm_log_dbg (LOGD_CORE, "disown %s singleton (%p)", G_OBJECT_TYPE_NAME (instance), instance);
136
137                 g_object_unref (instance);
138         }
139 }
140
141 void
142 _nm_singleton_instance_register_destruction (GObject *instance)
143 {
144         g_return_if_fail (G_IS_OBJECT (instance));
145
146         /* Don't allow registration after shutdown. We only destroy the singletons
147          * once. */
148         g_return_if_fail (!_singletons_shutdown);
149
150         g_object_weak_ref (instance, _nm_singleton_instance_weak_cb, NULL);
151
152         _singletons = g_slist_prepend (_singletons, instance);
153 }
154
155 /*****************************************************************************/
156
157 gint
158 nm_utils_ascii_str_to_bool (const char *str,
159                             gint default_value)
160 {
161         gsize len;
162         char *s = NULL;
163
164         if (!str)
165                 return default_value;
166
167         while (str[0] && g_ascii_isspace (str[0]))
168                 str++;
169
170         if (!str[0])
171                 return default_value;
172
173         len = strlen (str);
174         if (g_ascii_isspace (str[len - 1])) {
175                 s = g_strdup (str);
176                 g_strchomp (s);
177                 str = s;
178         }
179
180         if (!g_ascii_strcasecmp (str, "true") || !g_ascii_strcasecmp (str, "yes") || !g_ascii_strcasecmp (str, "on") || !g_ascii_strcasecmp (str, "1"))
181                 default_value = TRUE;
182         else if (!g_ascii_strcasecmp (str, "false") || !g_ascii_strcasecmp (str, "no") || !g_ascii_strcasecmp (str, "off") || !g_ascii_strcasecmp (str, "0"))
183                 default_value = FALSE;
184         if (s)
185                 g_free (s);
186         return default_value;
187 }
188
189 /*****************************************************************************/
190
191 /*
192  * nm_ethernet_address_is_valid:
193  * @addr: pointer to a binary or ASCII Ethernet address
194  * @len: length of @addr, or -1 if @addr is ASCII
195  *
196  * Compares an Ethernet address against known invalid addresses.
197
198  * Returns: %TRUE if @addr is a valid Ethernet address, %FALSE if it is not.
199  */
200 gboolean
201 nm_ethernet_address_is_valid (gconstpointer addr, gssize len)
202 {
203         guint8 invalid_addr[4][ETH_ALEN] = {
204             {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF},
205             {0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
206             {0x44, 0x44, 0x44, 0x44, 0x44, 0x44},
207             {0x00, 0x30, 0xb4, 0x00, 0x00, 0x00}, /* prism54 dummy MAC */
208         };
209         guint8 addr_bin[ETH_ALEN];
210         guint i;
211
212         if (!addr) {
213                 g_return_val_if_fail (len == -1 || len == ETH_ALEN, FALSE);
214                 return FALSE;
215         }
216
217         if (len == -1) {
218                 if (!nm_utils_hwaddr_aton (addr, addr_bin, ETH_ALEN))
219                         return FALSE;
220                 addr = addr_bin;
221         } else if (len != ETH_ALEN)
222                 g_return_val_if_reached (FALSE);
223
224         /* Check for multicast address */
225         if ((((guint8 *) addr)[0]) & 0x01)
226                 return FALSE;
227
228         for (i = 0; i < G_N_ELEMENTS (invalid_addr); i++) {
229                 if (nm_utils_hwaddr_matches (addr, ETH_ALEN, invalid_addr[i], ETH_ALEN))
230                         return FALSE;
231         }
232
233         return TRUE;
234 }
235
236
237 /* nm_utils_ip4_address_clear_host_address:
238  * @addr: source ip6 address
239  * @plen: prefix length of network
240  *
241  * returns: the input address, with the host address set to 0.
242  */
243 in_addr_t
244 nm_utils_ip4_address_clear_host_address (in_addr_t addr, guint8 plen)
245 {
246         return addr & nm_utils_ip4_prefix_to_netmask (plen);
247 }
248
249 /* nm_utils_ip6_address_clear_host_address:
250  * @dst: destination output buffer, will contain the network part of the @src address
251  * @src: source ip6 address
252  * @plen: prefix length of network
253  *
254  * Note: this function is self assignment safe, to update @src inplace, set both
255  * @dst and @src to the same destination.
256  */
257 const struct in6_addr *
258 nm_utils_ip6_address_clear_host_address (struct in6_addr *dst, const struct in6_addr *src, guint8 plen)
259 {
260         g_return_val_if_fail (plen <= 128, NULL);
261         g_return_val_if_fail (src, NULL);
262         g_return_val_if_fail (dst, NULL);
263
264         if (plen < 128) {
265                 guint nbytes = plen / 8;
266                 guint nbits = plen % 8;
267
268                 if (nbytes && dst != src)
269                         memcpy (dst, src, nbytes);
270                 if (nbits) {
271                         dst->s6_addr[nbytes] = (src->s6_addr[nbytes] & (0xFF << (8 - nbits)));
272                         nbytes++;
273                 }
274                 if (nbytes <= 15)
275                         memset (&dst->s6_addr[nbytes], 0, 16 - nbytes);
276         } else if (src != dst)
277                 *dst = *src;
278
279         return dst;
280 }
281
282 void
283 nm_utils_array_remove_at_indexes (GArray *array, const guint *indexes_to_delete, gsize len)
284 {
285         gsize elt_size;
286         guint index_to_delete;
287         guint i_src;
288         guint mm_src, mm_dst, mm_len;
289         gsize i_itd;
290         guint res_length;
291
292         g_return_if_fail (array);
293         if (!len)
294                 return;
295         g_return_if_fail (indexes_to_delete);
296
297         elt_size = g_array_get_element_size (array);
298
299         i_itd = 0;
300         index_to_delete = indexes_to_delete[0];
301         if (index_to_delete >= array->len)
302                 g_return_if_reached ();
303
304         res_length = array->len - 1;
305
306         mm_dst = index_to_delete;
307         mm_src = index_to_delete;
308         mm_len = 0;
309
310         for (i_src = index_to_delete; i_src < array->len; i_src++) {
311                 if (i_src < index_to_delete)
312                         mm_len++;
313                 else {
314                         /* we require indexes_to_delete to contain non-repeated, ascending
315                          * indexes. Otherwise we would need to presort the indexes. */
316                         while (TRUE) {
317                                 guint dd;
318
319                                 if (i_itd + 1 >= len) {
320                                         index_to_delete = G_MAXUINT;
321                                         break;
322                                 }
323
324                                 dd = indexes_to_delete[++i_itd];
325                                 if (dd > index_to_delete) {
326                                         if (dd >= array->len)
327                                                 g_warn_if_reached ();
328                                         else {
329                                                 g_assert (res_length > 0);
330                                                 res_length--;
331                                         }
332                                         index_to_delete = dd;
333                                         break;
334                                 }
335                                 g_warn_if_reached ();
336                         }
337
338                         if (mm_len) {
339                                 memmove (&array->data[mm_dst * elt_size],
340                                          &array->data[mm_src * elt_size],
341                                          mm_len * elt_size);
342                                 mm_dst += mm_len;
343                                 mm_src += mm_len + 1;
344                                 mm_len = 0;
345                         } else
346                                 mm_src++;
347                 }
348         }
349         if (mm_len) {
350                 memmove (&array->data[mm_dst * elt_size],
351                          &array->data[mm_src * elt_size],
352                          mm_len * elt_size);
353         }
354         g_array_set_size (array, res_length);
355 }
356
357 int
358 nm_spawn_process (const char *args, GError **error)
359 {
360         GError *local = NULL;
361         gint num_args;
362         char **argv = NULL;
363         int status = -1;
364
365         g_return_val_if_fail (args != NULL, -1);
366         g_return_val_if_fail (!error || !*error, -1);
367
368         if (g_shell_parse_argv (args, &num_args, &argv, &local)) {
369                 g_spawn_sync ("/", argv, NULL, 0, NULL, NULL, NULL, NULL, &status, &local);
370                 g_strfreev (argv);
371         }
372
373         if (local) {
374                 nm_log_warn (LOGD_CORE, "could not spawn process '%s': %s", args, local->message);
375                 g_propagate_error (error, local);
376         }
377
378         return status;
379 }
380
381 static const char *
382 _trunk_first_line (char *str)
383 {
384         char *s;
385
386         s = strchr (str, '\n');
387         if (s)
388                 s[0] = '\0';
389         return str;
390 }
391
392 int
393 nm_utils_modprobe (GError **error, gboolean suppress_error_logging, const char *arg1, ...)
394 {
395         gs_unref_ptrarray GPtrArray *argv = NULL;
396         int exit_status;
397         gs_free char *_log_str = NULL;
398 #define ARGV_TO_STR(argv)   (_log_str ? _log_str : (_log_str = g_strjoinv (" ", (char **) argv->pdata)))
399         GError *local = NULL;
400         va_list ap;
401         NMLogLevel llevel = suppress_error_logging ? LOGL_DEBUG : LOGL_ERR;
402         gs_free char *std_out = NULL, *std_err = NULL;
403
404         g_return_val_if_fail (!error || !*error, -1);
405         g_return_val_if_fail (arg1, -1);
406
407         /* construct the argument list */
408         argv = g_ptr_array_sized_new (4);
409         g_ptr_array_add (argv, "/sbin/modprobe");
410         g_ptr_array_add (argv, (char *) arg1);
411
412         va_start (ap, arg1);
413         while ((arg1 = va_arg (ap, const char *)))
414                 g_ptr_array_add (argv, (char *) arg1);
415         va_end (ap);
416
417         g_ptr_array_add (argv, NULL);
418
419         nm_log_dbg (LOGD_CORE, "modprobe: '%s'", ARGV_TO_STR (argv));
420         if (!g_spawn_sync (NULL, (char **) argv->pdata, NULL, 0, NULL, NULL, &std_out, &std_err, &exit_status, &local)) {
421                 nm_log (llevel, LOGD_CORE, "modprobe: '%s' failed: %s", ARGV_TO_STR (argv), local->message);
422                 g_propagate_error (error, local);
423                 return -1;
424         } else if (exit_status != 0) {
425                 nm_log (llevel, LOGD_CORE, "modprobe: '%s' exited with error %d%s%s%s%s%s%s", ARGV_TO_STR (argv), exit_status,
426                         std_out&&*std_out ? " (" : "", std_out&&*std_out ? _trunk_first_line (std_out) : "", std_out&&*std_out ? ")" : "",
427                         std_err&&*std_err ? " (" : "", std_err&&*std_err ? _trunk_first_line (std_err) : "", std_err&&*std_err ? ")" : "");
428         }
429
430         return exit_status;
431 }
432
433 /**
434  * nm_utils_get_start_time_for_pid:
435  * @pid: the process identifier
436  * @out_state: return the state character, like R, S, Z. See `man 5 proc`.
437  * @out_ppid: parent process id
438  *
439  * Originally copied from polkit source (src/polkit/polkitunixprocess.c)
440  * and adjusted.
441  *
442  * Returns: the timestamp when the process started (by parsing /proc/$PID/stat).
443  * If an error occurs (e.g. the process does not exist), 0 is returned.
444  *
445  * The returned start time counts since boot, in the unit HZ (with HZ usually being (1/100) seconds)
446  **/
447 guint64
448 nm_utils_get_start_time_for_pid (pid_t pid, char *out_state, pid_t *out_ppid)
449 {
450         guint64 start_time;
451         char filename[256];
452         gs_free gchar *contents = NULL;
453         size_t length;
454         gs_strfreev gchar **tokens = NULL;
455         guint num_tokens;
456         gchar *p;
457         gchar *endp;
458         char state = '\0';
459         gint64 ppid = 0;
460
461         start_time = 0;
462         contents = NULL;
463
464         g_return_val_if_fail (pid > 0, 0);
465
466         nm_sprintf_buf (filename, "/proc/%"G_GUINT64_FORMAT"/stat", (guint64) pid);
467
468         if (!g_file_get_contents (filename, &contents, &length, NULL))
469                 goto out;
470
471         /* start time is the token at index 19 after the '(process name)' entry - since only this
472          * field can contain the ')' character, search backwards for this to avoid malicious
473          * processes trying to fool us
474          */
475         p = strrchr (contents, ')');
476         if (p == NULL)
477                 goto out;
478         p += 2; /* skip ') ' */
479         if (p - contents >= (int) length)
480                 goto out;
481
482         state = p[0];
483
484         tokens = g_strsplit (p, " ", 0);
485
486         num_tokens = g_strv_length (tokens);
487
488         if (num_tokens < 20)
489                 goto out;
490
491         if (out_ppid)
492                 ppid = _nm_utils_ascii_str_to_int64 (tokens[1], 10, 1, G_MAXINT, 0);
493
494         errno = 0;
495         start_time = strtoull (tokens[19], &endp, 10);
496         if (*endp != '\0' || errno != 0)
497                 start_time = 0;
498
499 out:
500         if (out_state)
501                 *out_state = state;
502         if (out_ppid)
503                 *out_ppid = ppid;
504
505         return start_time;
506 }
507
508 /******************************************************************************************/
509
510 typedef struct {
511         pid_t pid;
512         NMLogDomain log_domain;
513         union {
514                 struct {
515                         gint64 wait_start_us;
516                         guint source_timeout_kill_id;
517                 } async;
518                 struct {
519                         gboolean success;
520                         int child_status;
521                 } sync;
522         };
523         NMUtilsKillChildAsyncCb callback;
524         void *user_data;
525
526         char log_name[1]; /* variable-length object, must be last element!! */
527 } KillChildAsyncData;
528
529 #define LOG_NAME_FMT "kill child process '%s' (%ld)"
530 #define LOG_NAME_PROCESS_FMT "kill process '%s' (%ld)"
531 #define LOG_NAME_ARGS log_name,(long)pid
532
533 static KillChildAsyncData *
534 _kc_async_data_alloc (pid_t pid, NMLogDomain log_domain, const char *log_name, NMUtilsKillChildAsyncCb callback, void *user_data)
535 {
536         KillChildAsyncData *data;
537         size_t log_name_len;
538
539         /* append the name at the end of our KillChildAsyncData. */
540         log_name_len = strlen (LOG_NAME_FMT) + 20 + strlen (log_name);
541         data = g_malloc (sizeof (KillChildAsyncData) - 1 + log_name_len);
542         g_snprintf (data->log_name, log_name_len, LOG_NAME_FMT, LOG_NAME_ARGS);
543
544         data->pid = pid;
545         data->user_data = user_data;
546         data->callback = callback;
547         data->log_domain = log_domain;
548
549         return data;
550 }
551
552 #define KC_EXIT_TO_STRING_BUF_SIZE 128
553 static const char *
554 _kc_exit_to_string (char *buf, int exit)
555 #define _kc_exit_to_string(buf, exit) ( G_STATIC_ASSERT_EXPR(sizeof (buf) == KC_EXIT_TO_STRING_BUF_SIZE && sizeof ((buf)[0]) == 1), _kc_exit_to_string (buf, exit) )
556 {
557         if (WIFEXITED (exit))
558                 g_snprintf (buf, KC_EXIT_TO_STRING_BUF_SIZE, "normally with status %d", WEXITSTATUS (exit));
559         else if (WIFSIGNALED (exit))
560                 g_snprintf (buf, KC_EXIT_TO_STRING_BUF_SIZE, "by signal %d", WTERMSIG (exit));
561         else
562                 g_snprintf (buf, KC_EXIT_TO_STRING_BUF_SIZE, "with unexpected status %d", exit);
563         return buf;
564 }
565
566 static const char *
567 _kc_signal_to_string (int sig)
568 {
569         switch (sig) {
570         case 0:  return "no signal (0)";
571         case SIGKILL:  return "SIGKILL (" G_STRINGIFY (SIGKILL) ")";
572         case SIGTERM:  return "SIGTERM (" G_STRINGIFY (SIGTERM) ")";
573         default:
574                 return "Unexpected signal";
575         }
576 }
577
578 #define KC_WAITED_TO_STRING 100
579 static const char *
580 _kc_waited_to_string (char *buf, gint64 wait_start_us)
581 #define _kc_waited_to_string(buf, wait_start_us) ( G_STATIC_ASSERT_EXPR(sizeof (buf) == KC_WAITED_TO_STRING && sizeof ((buf)[0]) == 1), _kc_waited_to_string (buf, wait_start_us) )
582 {
583         g_snprintf (buf, KC_WAITED_TO_STRING, " (%ld usec elapsed)", (long) (nm_utils_get_monotonic_timestamp_us () - wait_start_us));
584         return buf;
585 }
586
587 static void
588 _kc_cb_watch_child (GPid pid, gint status, gpointer user_data)
589 {
590         KillChildAsyncData *data = user_data;
591         char buf_exit[KC_EXIT_TO_STRING_BUF_SIZE], buf_wait[KC_WAITED_TO_STRING];
592
593         if (data->async.source_timeout_kill_id)
594                 g_source_remove (data->async.source_timeout_kill_id);
595
596         nm_log_dbg (data->log_domain, "%s: terminated %s%s",
597                     data->log_name, _kc_exit_to_string (buf_exit, status),
598                     _kc_waited_to_string (buf_wait, data->async.wait_start_us));
599
600         if (data->callback)
601                 data->callback (pid, TRUE, status, data->user_data);
602
603         g_free (data);
604 }
605
606 static gboolean
607 _kc_cb_timeout_grace_period (void *user_data)
608 {
609         KillChildAsyncData *data = user_data;
610         int ret, errsv;
611
612         data->async.source_timeout_kill_id = 0;
613
614         if ((ret = kill (data->pid, SIGKILL)) != 0) {
615                 errsv = errno;
616                 /* ESRCH means, process does not exist or is already a zombie. */
617                 if (errsv != ESRCH) {
618                         nm_log_err (LOGD_CORE | data->log_domain, "%s: kill(SIGKILL) returned unexpected return value %d: (%s, %d)",
619                                     data->log_name, ret, strerror (errsv), errsv);
620                 }
621         } else {
622                 nm_log_dbg (data->log_domain, "%s: process not terminated after %ld usec. Sending SIGKILL signal",
623                             data->log_name, (long) (nm_utils_get_monotonic_timestamp_us () - data->async.wait_start_us));
624         }
625
626         return G_SOURCE_REMOVE;
627 }
628
629 static gboolean
630 _kc_invoke_callback_idle (gpointer user_data)
631 {
632         KillChildAsyncData *data = user_data;
633
634         if (data->sync.success) {
635                 char buf_exit[KC_EXIT_TO_STRING_BUF_SIZE];
636
637                 nm_log_dbg (data->log_domain, "%s: invoke callback: terminated %s",
638                             data->log_name, _kc_exit_to_string (buf_exit, data->sync.child_status));
639         } else
640                 nm_log_dbg (data->log_domain, "%s: invoke callback: killing child failed", data->log_name);
641
642         data->callback (data->pid, data->sync.success, data->sync.child_status, data->user_data);
643         g_free (data);
644
645         return G_SOURCE_REMOVE;
646 }
647
648 static void
649 _kc_invoke_callback (pid_t pid, NMLogDomain log_domain, const char *log_name, NMUtilsKillChildAsyncCb callback, void *user_data, gboolean success, int child_status)
650 {
651         KillChildAsyncData *data;
652
653         if (!callback)
654                 return;
655
656         data = _kc_async_data_alloc (pid, log_domain, log_name, callback, user_data);
657         data->sync.success = success;
658         data->sync.child_status = child_status;
659
660         g_idle_add (_kc_invoke_callback_idle, data);
661 }
662
663 /* nm_utils_kill_child_async:
664  * @pid: the process id of the process to kill
665  * @sig: signal to send initially. Set to 0 to send not signal.
666  * @log_domain: the logging domain used for logging (LOGD_NONE to suppress logging)
667  * @log_name: for logging, the name of the processes to kill
668  * @wait_before_kill_msec: Waittime in milliseconds before sending %SIGKILL signal. Set this value
669  * to zero, not to send %SIGKILL. If @sig is already %SIGKILL, this parameter is ignored.
670  * @callback: (allow-none): callback after the child terminated. This function will always
671  *   be invoked asynchronously.
672  * @user_data: passed on to callback
673  *
674  * Uses g_child_watch_add(), so note the glib comment: if you obtain pid from g_spawn_async() or
675  * g_spawn_async_with_pipes() you will need to pass %G_SPAWN_DO_NOT_REAP_CHILD as flag to the spawn
676  * function for the child watching to work.
677  * Also note, that you must g_source_remove() any other child watchers for @pid because glib
678  * supports only one watcher per child.
679  **/
680 void
681 nm_utils_kill_child_async (pid_t pid, int sig, NMLogDomain log_domain,
682                            const char *log_name, guint32 wait_before_kill_msec,
683                            NMUtilsKillChildAsyncCb callback, void *user_data)
684 {
685         int status = 0, errsv;
686         pid_t ret;
687         KillChildAsyncData *data;
688         char buf_exit[KC_EXIT_TO_STRING_BUF_SIZE];
689
690         g_return_if_fail (pid > 0);
691         g_return_if_fail (log_name != NULL);
692
693         /* let's see if the child already terminated... */
694         ret = waitpid (pid, &status, WNOHANG);
695         if (ret > 0) {
696                 nm_log_dbg (log_domain, LOG_NAME_FMT ": process %ld already terminated %s",
697                             LOG_NAME_ARGS, (long) ret, _kc_exit_to_string (buf_exit, status));
698                 _kc_invoke_callback (pid, log_domain, log_name, callback, user_data, TRUE, status);
699                 return;
700         } else if (ret != 0) {
701                 errsv = errno;
702                 /* ECHILD means, the process is not a child/does not exist or it has SIGCHILD blocked. */
703                 if (errsv != ECHILD) {
704                         nm_log_err (LOGD_CORE | log_domain, LOG_NAME_FMT ": unexpected error while waitpid: %s (%d)",
705                                     LOG_NAME_ARGS, strerror (errsv), errsv);
706                         _kc_invoke_callback (pid, log_domain, log_name, callback, user_data, FALSE, -1);
707                         return;
708                 }
709         }
710
711         /* send the first signal. */
712         if (kill (pid, sig) != 0) {
713                 errsv = errno;
714                 /* ESRCH means, process does not exist or is already a zombie. */
715                 if (errsv != ESRCH) {
716                         nm_log_err (LOGD_CORE | log_domain, LOG_NAME_FMT ": unexpected error sending %s: %s (%d)",
717                                     LOG_NAME_ARGS, _kc_signal_to_string (sig), strerror (errsv), errsv);
718                         _kc_invoke_callback (pid, log_domain, log_name, callback, user_data, FALSE, -1);
719                         return;
720                 }
721
722                 /* let's try again with waitpid, probably there was a race... */
723                 ret = waitpid (pid, &status, 0);
724                 if (ret > 0) {
725                         nm_log_dbg (log_domain, LOG_NAME_FMT ": process %ld already terminated %s",
726                                     LOG_NAME_ARGS, (long) ret, _kc_exit_to_string (buf_exit, status));
727                         _kc_invoke_callback (pid, log_domain, log_name, callback, user_data, TRUE, status);
728                 } else {
729                         errsv = errno;
730                         nm_log_err (LOGD_CORE | log_domain, LOG_NAME_FMT ": failed due to unexpected return value %ld by waitpid (%s, %d) after sending %s",
731                                     LOG_NAME_ARGS, (long) ret, strerror (errsv), errsv, _kc_signal_to_string (sig));
732                         _kc_invoke_callback (pid, log_domain, log_name, callback, user_data, FALSE, -1);
733                 }
734                 return;
735         }
736
737         data = _kc_async_data_alloc (pid, log_domain, log_name, callback, user_data);
738         data->async.wait_start_us = nm_utils_get_monotonic_timestamp_us ();
739
740         if (sig != SIGKILL && wait_before_kill_msec > 0) {
741                 data->async.source_timeout_kill_id = g_timeout_add (wait_before_kill_msec, _kc_cb_timeout_grace_period, data);
742                 nm_log_dbg (log_domain, "%s: wait for process to terminate after sending %s (send SIGKILL in %ld milliseconds)...",
743                             data->log_name,  _kc_signal_to_string (sig), (long) wait_before_kill_msec);
744         } else {
745                 data->async.source_timeout_kill_id = 0;
746                 nm_log_dbg (log_domain, "%s: wait for process to terminate after sending %s...",
747                             data->log_name, _kc_signal_to_string (sig));
748         }
749
750         g_child_watch_add (pid, _kc_cb_watch_child, data);
751 }
752
753 static inline gulong
754 _sleep_duration_convert_ms_to_us (guint32 sleep_duration_msec)
755 {
756         if (sleep_duration_msec > 0) {
757                 guint64 x = (gint64) sleep_duration_msec * (guint64) 1000L;
758
759                 return x < G_MAXULONG ? (gulong) x : G_MAXULONG;
760         }
761         return G_USEC_PER_SEC / 20;
762 }
763
764 /* nm_utils_kill_child_sync:
765  * @pid: process id to kill
766  * @sig: signal to sent initially. If 0, no signal is sent. If %SIGKILL, the
767  * second %SIGKILL signal is not sent after @wait_before_kill_msec milliseconds.
768  * @log_domain: log debug information for this domain. Errors and warnings are logged both
769  * as %LOGD_CORE and @log_domain.
770  * @log_name: name of the process to kill for logging.
771  * @child_status: (out) (allow-none): return the exit status of the child, if no error occured.
772  * @wait_before_kill_msec: Waittime in milliseconds before sending %SIGKILL signal. Set this value
773  * to zero, not to send %SIGKILL. If @sig is already %SIGKILL, this parameter has not effect.
774  * @sleep_duration_msec: the synchronous function sleeps repeatedly waiting for the child to terminate.
775  * Set to zero, to use the default (meaning 20 wakeups per seconds).
776  *
777  * Kill a child process synchronously and wait. The function first checks if the child already terminated
778  * and if it did, return the exit status. Otherwise send one @sig signal. @sig  will always be
779  * sent unless the child already exited. If the child does not exit within @wait_before_kill_msec milliseconds,
780  * the function will send %SIGKILL and waits for the child indefinitly. If @wait_before_kill_msec is zero, no
781  * %SIGKILL signal will be sent.
782  *
783  * In case of error, errno is preserved to contain the last reason of failure.
784  **/
785 gboolean
786 nm_utils_kill_child_sync (pid_t pid, int sig, NMLogDomain log_domain, const char *log_name,
787                           int *child_status, guint32 wait_before_kill_msec,
788                           guint32 sleep_duration_msec)
789 {
790         int status = 0, errsv = 0;
791         pid_t ret;
792         gboolean success = FALSE;
793         gboolean was_waiting = FALSE, send_kill = FALSE;
794         char buf_exit[KC_EXIT_TO_STRING_BUF_SIZE];
795         char buf_wait[KC_WAITED_TO_STRING];
796         gint64 wait_start_us;
797
798         g_return_val_if_fail (pid > 0, FALSE);
799         g_return_val_if_fail (log_name != NULL, FALSE);
800
801         /* check if the child process already terminated... */
802         ret = waitpid (pid, &status, WNOHANG);
803         if (ret > 0) {
804                 nm_log_dbg (log_domain, LOG_NAME_FMT ": process %ld already terminated %s",
805                             LOG_NAME_ARGS, (long) ret, _kc_exit_to_string (buf_exit, status));
806                 success = TRUE;
807                 goto out;
808         } else if (ret != 0) {
809                 errsv = errno;
810                 /* ECHILD means, the process is not a child/does not exist or it has SIGCHILD blocked. */
811                 if (errsv != ECHILD) {
812                         nm_log_err (LOGD_CORE | log_domain, LOG_NAME_FMT ": unexpected error while waitpid: %s (%d)",
813                                     LOG_NAME_ARGS, strerror (errsv), errsv);
814                         goto out;
815                 }
816         }
817
818         /* send first signal @sig */
819         if (kill (pid, sig) != 0) {
820                 errsv = errno;
821                 /* ESRCH means, process does not exist or is already a zombie. */
822                 if (errsv != ESRCH) {
823                         nm_log_err (LOGD_CORE | log_domain, LOG_NAME_FMT ": failed to send %s: %s (%d)",
824                                     LOG_NAME_ARGS, _kc_signal_to_string (sig), strerror (errsv), errsv);
825                 } else {
826                         /* let's try again with waitpid, probably there was a race... */
827                         ret = waitpid (pid, &status, 0);
828                         if (ret > 0) {
829                                 nm_log_dbg (log_domain, LOG_NAME_FMT ": process %ld already terminated %s",
830                                             LOG_NAME_ARGS, (long) ret, _kc_exit_to_string (buf_exit, status));
831                                 success = TRUE;
832                         } else {
833                                 errsv = errno;
834                                 nm_log_err (LOGD_CORE | log_domain, LOG_NAME_FMT ": failed due to unexpected return value %ld by waitpid (%s, %d) after sending %s",
835                                             LOG_NAME_ARGS, (long) ret, strerror (errsv), errsv, _kc_signal_to_string (sig));
836                         }
837                 }
838                 goto out;
839         }
840
841         wait_start_us = nm_utils_get_monotonic_timestamp_us ();
842
843         /* wait for the process to terminated... */
844         if (sig != SIGKILL) {
845                 gint64 wait_until, now;
846                 gulong sleep_time, sleep_duration_usec;
847                 int loop_count = 0;
848
849                 sleep_duration_usec = _sleep_duration_convert_ms_to_us (sleep_duration_msec);
850                 wait_until = wait_before_kill_msec <= 0 ? 0 : wait_start_us + (((gint64) wait_before_kill_msec) * 1000L);
851
852                 while (TRUE) {
853                         ret = waitpid (pid, &status, WNOHANG);
854                         if (ret > 0) {
855                                 nm_log_dbg (log_domain, LOG_NAME_FMT ": after sending %s, process %ld exited %s%s",
856                                             LOG_NAME_ARGS, _kc_signal_to_string (sig), (long) ret, _kc_exit_to_string (buf_exit, status),
857                                             was_waiting ? _kc_waited_to_string (buf_wait, wait_start_us) : "");
858                                 success = TRUE;
859                                 goto out;
860                         }
861                         if (ret == -1) {
862                                 errsv = errno;
863                                 /* ECHILD means, the process is not a child/does not exist or it has SIGCHILD blocked. */
864                                 if (errsv != ECHILD) {
865                                         nm_log_err (LOGD_CORE | log_domain, LOG_NAME_FMT ": after sending %s, waitpid failed with %s (%d)%s",
866                                                     LOG_NAME_ARGS, _kc_signal_to_string (sig), strerror (errsv), errsv,
867                                                    was_waiting ? _kc_waited_to_string (buf_wait, wait_start_us) : "");
868                                         goto out;
869                                 }
870                         }
871
872                         if (!wait_until)
873                                 break;
874
875                         now = nm_utils_get_monotonic_timestamp_us ();
876                         if (now >= wait_until)
877                                 break;
878
879                         if (!was_waiting) {
880                                 nm_log_dbg (log_domain, LOG_NAME_FMT ": waiting up to %ld milliseconds for process to terminate normally after sending %s...",
881                                             LOG_NAME_ARGS, (long) MAX (wait_before_kill_msec, 0), _kc_signal_to_string (sig));
882                                 was_waiting = TRUE;
883                         }
884
885                         sleep_time = MIN (wait_until - now, sleep_duration_usec);
886                         if (loop_count < 20) {
887                                 /* At the beginning we expect the process to die fast.
888                                  * Limit the sleep time, the limit doubles with every iteration. */
889                                 sleep_time = MIN (sleep_time, (((guint64) 1) << loop_count) * G_USEC_PER_SEC / 2000);
890                                 loop_count++;
891                         }
892                         g_usleep (sleep_time);
893                 }
894
895                 /* send SIGKILL, if called with @wait_before_kill_msec > 0 */
896                 if (wait_until) {
897                         nm_log_dbg (log_domain, LOG_NAME_FMT ": sending SIGKILL...", LOG_NAME_ARGS);
898
899                         send_kill = TRUE;
900                         if (kill (pid, SIGKILL) != 0) {
901                                 errsv = errno;
902                                 /* ESRCH means, process does not exist or is already a zombie. */
903                                 if (errsv != ESRCH) {
904                                         nm_log_err (LOGD_CORE | log_domain, LOG_NAME_FMT ": failed to send SIGKILL (after sending %s), %s (%d)",
905                                                                 LOG_NAME_ARGS, _kc_signal_to_string (sig), strerror (errsv), errsv);
906                                         goto out;
907                                 }
908                         }
909                 }
910         }
911
912         if (!was_waiting) {
913                 nm_log_dbg (log_domain, LOG_NAME_FMT ": waiting for process to terminate after sending %s%s...",
914                             LOG_NAME_ARGS, _kc_signal_to_string (sig), send_kill ? " and SIGKILL" : "");
915         }
916
917         /* block until the child terminates. */
918         while ((ret = waitpid (pid, &status, 0)) <= 0) {
919                 errsv = errno;
920
921                 if (errsv != EINTR) {
922                         nm_log_err (LOGD_CORE | log_domain, LOG_NAME_FMT ": after sending %s%s, waitpid failed with %s (%d)%s",
923                                     LOG_NAME_ARGS, _kc_signal_to_string (sig), send_kill ? " and SIGKILL" : "", strerror (errsv), errsv,
924                                     _kc_waited_to_string (buf_wait, wait_start_us));
925                         goto out;
926                 }
927         }
928
929         nm_log_dbg (log_domain, LOG_NAME_FMT ": after sending %s%s, process %ld exited %s%s",
930                     LOG_NAME_ARGS, _kc_signal_to_string (sig), send_kill ? " and SIGKILL" : "", (long) ret,
931                     _kc_exit_to_string (buf_exit, status), _kc_waited_to_string (buf_wait, wait_start_us));
932         success = TRUE;
933 out:
934         if (child_status)
935                 *child_status = success ? status : -1;
936         errno = success ? 0 : errsv;
937         return success;
938 }
939
940 /* nm_utils_kill_process_sync:
941  * @pid: process id to kill
942  * @start_time: the start time of the process to kill (as obtained by nm_utils_get_start_time_for_pid()).
943  *   This is an optional argument, to avoid (somewhat) killing the wrong process as @pid
944  *   might get recycled. You can pass 0, to not provide this parameter.
945  * @sig: signal to sent initially. If 0, no signal is sent. If %SIGKILL, the
946  *   second %SIGKILL signal is not sent after @wait_before_kill_msec milliseconds.
947  * @log_domain: log debug information for this domain. Errors and warnings are logged both
948  *   as %LOGD_CORE and @log_domain.
949  * @log_name: name of the process to kill for logging.
950  * @wait_before_kill_msec: Waittime in milliseconds before sending %SIGKILL signal. Set this value
951  *   to zero, not to send %SIGKILL. If @sig is already %SIGKILL, this parameter has no effect.
952  *   If @max_wait_msec is set but less then @wait_before_kill_msec, the final %SIGKILL will also
953  *   not be send.
954  * @sleep_duration_msec: the synchronous function sleeps repeatedly waiting for the child to terminate.
955  *   Set to zero, to use the default (meaning 20 wakeups per seconds).
956  * @max_wait_msec: if 0, waits indefinitely until the process is gone (or a zombie). Otherwise, this
957  *   is the maxium wait time until returning. If @max_wait_msec is non-zero but smaller then @wait_before_kill_msec,
958  *   we will not send a final %SIGKILL.
959  *
960  * Kill a non-child process synchronously and wait. This function will not return before the
961  * process with PID @pid is gone, the process is a zombie, or @max_wait_msec expires.
962  **/
963 void
964 nm_utils_kill_process_sync (pid_t pid, guint64 start_time, int sig, NMLogDomain log_domain,
965                             const char *log_name, guint32 wait_before_kill_msec,
966                             guint32 sleep_duration_msec, guint32 max_wait_msec)
967 {
968         int errsv;
969         guint64 start_time0;
970         gint64 wait_until_sigkill, now, wait_start_us, max_wait_until;
971         gulong sleep_time, sleep_duration_usec;
972         int loop_count = 0;
973         gboolean was_waiting = FALSE;
974         char buf_wait[KC_WAITED_TO_STRING];
975         char p_state;
976
977         g_return_if_fail (pid > 0);
978         g_return_if_fail (log_name != NULL);
979
980         start_time0 = nm_utils_get_start_time_for_pid (pid, &p_state, NULL);
981         if (start_time0 == 0) {
982                 nm_log_dbg (log_domain, LOG_NAME_PROCESS_FMT ": cannot kill process %ld because it seems already gone",
983                             LOG_NAME_ARGS, (long int) pid);
984                 return;
985         }
986         if (start_time != 0 && start_time != start_time0) {
987                 nm_log_dbg (log_domain, LOG_NAME_PROCESS_FMT ": don't kill process %ld because the start_time is unexpectedly %lu instead of %ld",
988                             LOG_NAME_ARGS, (long int) pid, (long unsigned) start_time0, (long unsigned) start_time);
989                 return;
990         }
991
992         switch (p_state) {
993         case 'Z':
994         case 'x':
995         case 'X':
996                 nm_log_dbg (log_domain, LOG_NAME_PROCESS_FMT ": cannot kill process %ld because it is already a zombie (%c)",
997                             LOG_NAME_ARGS, (long int) pid, p_state);
998                 return;
999         default:
1000                 break;
1001         }
1002
1003         if (kill (pid, sig) != 0) {
1004                 errsv = errno;
1005                 /* ESRCH means, process does not exist or is already a zombie. */
1006                 if (errsv == ESRCH) {
1007                         nm_log_dbg (log_domain, LOG_NAME_PROCESS_FMT ": failed to send %s because process seems gone",
1008                                     LOG_NAME_ARGS, _kc_signal_to_string (sig));
1009                 } else {
1010                         nm_log_warn (LOGD_CORE | log_domain, LOG_NAME_PROCESS_FMT ": failed to send %s: %s (%d)",
1011                                      LOG_NAME_ARGS, _kc_signal_to_string (sig), strerror (errsv), errsv);
1012                 }
1013                 return;
1014         }
1015
1016         /* wait for the process to terminate... */
1017
1018         wait_start_us = nm_utils_get_monotonic_timestamp_us ();
1019
1020         sleep_duration_usec = _sleep_duration_convert_ms_to_us (sleep_duration_msec);
1021         if (sig != SIGKILL && wait_before_kill_msec)
1022                 wait_until_sigkill = wait_start_us + (((gint64) wait_before_kill_msec) * 1000L);
1023         else
1024                 wait_until_sigkill = 0;
1025         if (max_wait_msec > 0) {
1026                 max_wait_until = wait_start_us + (((gint64) max_wait_msec) * 1000L);
1027                 if (wait_until_sigkill > 0 && wait_until_sigkill > max_wait_msec)
1028                         wait_until_sigkill = 0;
1029         } else
1030                 max_wait_until = 0;
1031
1032         while (TRUE) {
1033                 start_time = nm_utils_get_start_time_for_pid (pid, &p_state, NULL);
1034
1035                 if (start_time != start_time0) {
1036                         nm_log_dbg (log_domain, LOG_NAME_PROCESS_FMT ": process is gone after sending signal %s%s",
1037                                     LOG_NAME_ARGS, _kc_signal_to_string (sig),
1038                                     was_waiting ? _kc_waited_to_string (buf_wait, wait_start_us) : "");
1039                         return;
1040                 }
1041                 switch (p_state) {
1042                 case 'Z':
1043                 case 'x':
1044                 case 'X':
1045                         nm_log_dbg (log_domain, LOG_NAME_PROCESS_FMT ": process is a zombie (%c) after sending signal %s%s",
1046                                     LOG_NAME_ARGS, p_state, _kc_signal_to_string (sig),
1047                                     was_waiting ? _kc_waited_to_string (buf_wait, wait_start_us) : "");
1048                         return;
1049                 default:
1050                         break;
1051                 }
1052
1053                 if (kill (pid, 0) != 0) {
1054                         errsv = errno;
1055                         /* ESRCH means, process does not exist or is already a zombie. */
1056                         if (errsv == ESRCH) {
1057                                 nm_log_dbg (log_domain, LOG_NAME_PROCESS_FMT ": process is gone or a zombie after sending signal %s%s",
1058                                             LOG_NAME_ARGS, _kc_signal_to_string (sig),
1059                                             was_waiting ? _kc_waited_to_string (buf_wait, wait_start_us) : "");
1060                         } else {
1061                                 nm_log_warn (LOGD_CORE | log_domain, LOG_NAME_PROCESS_FMT ": failed to kill(%ld, 0): %s (%d)%s",
1062                                              LOG_NAME_ARGS, (long int) pid, strerror (errsv), errsv,
1063                                              was_waiting ? _kc_waited_to_string (buf_wait, wait_start_us) : "");
1064                         }
1065                         return;
1066                 }
1067
1068                 sleep_time = sleep_duration_usec;
1069                 now = nm_utils_get_monotonic_timestamp_us ();
1070
1071                 if (   max_wait_until != 0
1072                     && now >= max_wait_until) {
1073                         if (wait_until_sigkill != 0) {
1074                                 /* wait_before_kill_msec is not larger then max_wait_until but we did not yet send
1075                                  * SIGKILL. Although we already reached our timeout, we don't want to skip sending
1076                                  * the signal. Even if we don't wait for the process to disappear. */
1077                                 nm_log_dbg (log_domain, LOG_NAME_PROCESS_FMT ": sending SIGKILL", LOG_NAME_ARGS);
1078                                 kill (pid, SIGKILL);
1079                         }
1080                         nm_log_warn (log_domain, LOG_NAME_PROCESS_FMT ": timeout %u msec waiting for process to disappear (after sending %s)%s",
1081                                      LOG_NAME_ARGS, (unsigned) max_wait_until, _kc_signal_to_string (sig),
1082                                      was_waiting ? _kc_waited_to_string (buf_wait, wait_start_us) : "");
1083                         return;
1084                 }
1085
1086                 if (wait_until_sigkill != 0) {
1087                         if (now >= wait_until_sigkill) {
1088                                 /* Still not dead. SIGKILL now... */
1089                                 nm_log_dbg (log_domain, LOG_NAME_PROCESS_FMT ": sending SIGKILL", LOG_NAME_ARGS);
1090                                 if (kill (pid, SIGKILL) != 0) {
1091                                         errsv = errno;
1092                                         /* ESRCH means, process does not exist or is already a zombie. */
1093                                         if (errsv != ESRCH) {
1094                                                 nm_log_dbg (log_domain, LOG_NAME_PROCESS_FMT ": process is gone or a zombie%s",
1095                                                             LOG_NAME_ARGS, _kc_waited_to_string (buf_wait, wait_start_us));
1096                                         } else {
1097                                                 nm_log_warn (LOGD_CORE | log_domain, LOG_NAME_PROCESS_FMT ": failed to send SIGKILL (after sending %s), %s (%d)%s",
1098                                                              LOG_NAME_ARGS, _kc_signal_to_string (sig), strerror (errsv), errsv,
1099                                                              _kc_waited_to_string (buf_wait, wait_start_us));
1100                                         }
1101                                         return;
1102                                 }
1103                                 sig = SIGKILL;
1104                                 wait_until_sigkill = 0;
1105                                 loop_count = 0; /* reset the loop_count. Now we really expect the process to die quickly. */
1106                         } else
1107                                 sleep_time = MIN (wait_until_sigkill - now, sleep_duration_usec);
1108                 }
1109
1110                 if (!was_waiting) {
1111                         if (wait_until_sigkill != 0) {
1112                                 nm_log_dbg (log_domain, LOG_NAME_PROCESS_FMT ": waiting up to %ld milliseconds for process to disappear before sending KILL signal after sending %s...",
1113                                             LOG_NAME_ARGS, (long) wait_before_kill_msec, _kc_signal_to_string (sig));
1114                         } else if (max_wait_until != 0) {
1115                                 nm_log_dbg (log_domain, LOG_NAME_PROCESS_FMT ": waiting up to %ld milliseconds for process to disappear after sending %s...",
1116                                             LOG_NAME_ARGS, (long) max_wait_msec, _kc_signal_to_string (sig));
1117                         } else {
1118                                 nm_log_dbg (log_domain, LOG_NAME_PROCESS_FMT ": waiting for process to disappear after sending %s...",
1119                                             LOG_NAME_ARGS, _kc_signal_to_string (sig));
1120                         }
1121                         was_waiting = TRUE;
1122                 }
1123
1124                 if (loop_count < 20) {
1125                         /* At the beginning we expect the process to die fast.
1126                          * Limit the sleep time, the limit doubles with every iteration. */
1127                         sleep_time = MIN (sleep_time, (((guint64) 1) << loop_count) * G_USEC_PER_SEC / 2000);
1128                         loop_count++;
1129                 }
1130                 g_usleep (sleep_time);
1131         }
1132 }
1133 #undef LOG_NAME_FMT
1134 #undef LOG_NAME_PROCESS_FMT
1135 #undef LOG_NAME_ARGS
1136
1137 const char *const NM_PATHS_DEFAULT[] = {
1138         PREFIX "/sbin/",
1139         PREFIX "/bin/",
1140         "/sbin/",
1141         "/usr/sbin/",
1142         "/usr/local/sbin/",
1143         "/bin/",
1144         "/usr/bin/",
1145         "/usr/local/bin/",
1146         NULL,
1147 };
1148
1149 const char *
1150 nm_utils_find_helper(const char *progname, const char *try_first, GError **error)
1151 {
1152         return nm_utils_file_search_in_paths (progname, try_first, NM_PATHS_DEFAULT, G_FILE_TEST_IS_EXECUTABLE, NULL, NULL, error);
1153 }
1154
1155 /******************************************************************************************/
1156
1157 #define MAC_TAG "mac:"
1158 #define INTERFACE_NAME_TAG "interface-name:"
1159 #define DEVICE_TYPE_TAG "type:"
1160 #define SUBCHAN_TAG "s390-subchannels:"
1161 #define EXCEPT_TAG "except:"
1162 #define MATCH_TAG_CONFIG_NM_VERSION             "nm-version:"
1163 #define MATCH_TAG_CONFIG_NM_VERSION_MIN         "nm-version-min:"
1164 #define MATCH_TAG_CONFIG_NM_VERSION_MAX         "nm-version-max:"
1165 #define MATCH_TAG_CONFIG_ENV                    "env:"
1166
1167 #define _spec_has_prefix(pspec, tag) \
1168         ({ \
1169                 const char **_spec = (pspec); \
1170                 gboolean _has = FALSE; \
1171                 \
1172                 if (!g_ascii_strncasecmp (*_spec, (""tag), NM_STRLEN (tag))) { \
1173                         *_spec += NM_STRLEN (tag); \
1174                         _has = TRUE; \
1175                 } \
1176                 _has; \
1177         })
1178
1179 static const char *
1180 _match_except (const char *spec_str, gboolean *out_except)
1181 {
1182         if (!g_ascii_strncasecmp (spec_str, EXCEPT_TAG, NM_STRLEN (EXCEPT_TAG))) {
1183                 spec_str += NM_STRLEN (EXCEPT_TAG);
1184                 *out_except = TRUE;
1185         } else
1186                 *out_except = FALSE;
1187         return spec_str;
1188 }
1189
1190 NMMatchSpecMatchType
1191 nm_match_spec_device_type (const GSList *specs, const char *device_type)
1192 {
1193         const GSList *iter;
1194         NMMatchSpecMatchType match = NM_MATCH_SPEC_NO_MATCH;
1195
1196         if (!device_type || !*device_type)
1197                 return NM_MATCH_SPEC_NO_MATCH;
1198
1199         for (iter = specs; iter; iter = g_slist_next (iter)) {
1200                 const char *spec_str = iter->data;
1201                 gboolean except;
1202
1203                 if (!spec_str || !*spec_str)
1204                         continue;
1205
1206                 spec_str = _match_except (spec_str, &except);
1207
1208                 if (g_ascii_strncasecmp (spec_str, DEVICE_TYPE_TAG, NM_STRLEN (DEVICE_TYPE_TAG)) != 0)
1209                         continue;
1210
1211                 spec_str += NM_STRLEN (DEVICE_TYPE_TAG);
1212                 if (strcmp (spec_str, device_type) == 0) {
1213                         if (except)
1214                                 return NM_MATCH_SPEC_NEG_MATCH;
1215                         match = NM_MATCH_SPEC_MATCH;
1216                 }
1217         }
1218         return match;
1219 }
1220
1221 NMMatchSpecMatchType
1222 nm_match_spec_hwaddr (const GSList *specs, const char *hwaddr)
1223 {
1224         const GSList *iter;
1225         NMMatchSpecMatchType match = NM_MATCH_SPEC_NO_MATCH;
1226
1227         g_return_val_if_fail (hwaddr != NULL, NM_MATCH_SPEC_NO_MATCH);
1228
1229         for (iter = specs; iter; iter = g_slist_next (iter)) {
1230                 const char *spec_str = iter->data;
1231                 gboolean except;
1232
1233                 if (!spec_str || !*spec_str)
1234                         continue;
1235
1236                 spec_str = _match_except (spec_str, &except);
1237
1238                 if (   !g_ascii_strncasecmp (spec_str, INTERFACE_NAME_TAG, NM_STRLEN (INTERFACE_NAME_TAG))
1239                     || !g_ascii_strncasecmp (spec_str, SUBCHAN_TAG, NM_STRLEN (SUBCHAN_TAG))
1240                     || !g_ascii_strncasecmp (spec_str, DEVICE_TYPE_TAG, NM_STRLEN (DEVICE_TYPE_TAG)))
1241                         continue;
1242
1243                 if (!g_ascii_strncasecmp (spec_str, MAC_TAG, NM_STRLEN (MAC_TAG)))
1244                         spec_str += NM_STRLEN (MAC_TAG);
1245                 else if (except)
1246                         continue;
1247
1248                 if (nm_utils_hwaddr_matches (spec_str, -1, hwaddr, -1)) {
1249                         if (except)
1250                                 return NM_MATCH_SPEC_NEG_MATCH;
1251                         match = NM_MATCH_SPEC_MATCH;
1252                 }
1253         }
1254         return match;
1255 }
1256
1257 NMMatchSpecMatchType
1258 nm_match_spec_interface_name (const GSList *specs, const char *interface_name)
1259 {
1260         const GSList *iter;
1261         NMMatchSpecMatchType match = NM_MATCH_SPEC_NO_MATCH;
1262
1263         g_return_val_if_fail (interface_name != NULL, NM_MATCH_SPEC_NO_MATCH);
1264
1265         for (iter = specs; iter; iter = g_slist_next (iter)) {
1266                 const char *spec_str = iter->data;
1267                 gboolean use_pattern = FALSE;
1268                 gboolean except;
1269
1270                 if (!spec_str || !*spec_str)
1271                         continue;
1272
1273                 spec_str = _match_except (spec_str, &except);
1274
1275                 if (   !g_ascii_strncasecmp (spec_str, MAC_TAG, NM_STRLEN (MAC_TAG))
1276                     || !g_ascii_strncasecmp (spec_str, SUBCHAN_TAG, NM_STRLEN (SUBCHAN_TAG))
1277                     || !g_ascii_strncasecmp (spec_str, DEVICE_TYPE_TAG, NM_STRLEN (DEVICE_TYPE_TAG)))
1278                         continue;
1279
1280                 if (!g_ascii_strncasecmp (spec_str, INTERFACE_NAME_TAG, NM_STRLEN (INTERFACE_NAME_TAG))) {
1281                         spec_str += NM_STRLEN (INTERFACE_NAME_TAG);
1282                         if (spec_str[0] == '=')
1283                                 spec_str += 1;
1284                         else {
1285                                 if (spec_str[0] == '~')
1286                                         spec_str += 1;
1287                                 use_pattern=TRUE;
1288                         }
1289                 } else if (except)
1290                         continue;
1291
1292                 if (   !strcmp (spec_str, interface_name)
1293                     || (use_pattern && g_pattern_match_simple (spec_str, interface_name))) {
1294                         if (except)
1295                                 return NM_MATCH_SPEC_NEG_MATCH;
1296                         match = NM_MATCH_SPEC_MATCH;
1297                 }
1298         }
1299         return match;
1300 }
1301
1302 #define BUFSIZE 10
1303
1304 static gboolean
1305 parse_subchannels (const char *subchannels, guint32 *a, guint32 *b, guint32 *c)
1306 {
1307         long unsigned int tmp;
1308         char buf[BUFSIZE + 1];
1309         const char *p = subchannels;
1310         int i = 0;
1311         char *pa = NULL, *pb = NULL, *pc = NULL;
1312
1313         g_return_val_if_fail (subchannels != NULL, FALSE);
1314         g_return_val_if_fail (a != NULL, FALSE);
1315         g_return_val_if_fail (*a == 0, FALSE);
1316         g_return_val_if_fail (b != NULL, FALSE);
1317         g_return_val_if_fail (*b == 0, FALSE);
1318         g_return_val_if_fail (c != NULL, FALSE);
1319         g_return_val_if_fail (*c == 0, FALSE);
1320
1321         /* sanity check */
1322         if (!g_ascii_isxdigit (subchannels[0]))
1323                 return FALSE;
1324
1325         /* Get the first channel */
1326         while (*p && (*p != ',')) {
1327                 if (!g_ascii_isxdigit (*p) && (*p != '.'))
1328                         return FALSE;  /* Invalid chars */
1329                 if (i >= BUFSIZE)
1330                         return FALSE;  /* Too long to be a subchannel */
1331                 buf[i++] = *p++;
1332         }
1333         buf[i] = '\0';
1334
1335         /* and grab each of its elements, there should be 3 */
1336         pa = &buf[0];
1337         pb = strchr (buf, '.');
1338         if (pb)
1339                 pc = strchr (pb + 1, '.');
1340         if (!pa || !pb || !pc)
1341                 return FALSE;
1342
1343         /* Split the string */
1344         *pb++ = '\0';
1345         *pc++ = '\0';
1346
1347         errno = 0;
1348         tmp = strtoul (pa, NULL, 16);
1349         if (errno)
1350                 return FALSE;
1351         *a = (guint32) tmp;
1352
1353         errno = 0;
1354         tmp = strtoul (pb, NULL, 16);
1355         if (errno)
1356                 return FALSE;
1357         *b = (guint32) tmp;
1358
1359         errno = 0;
1360         tmp = strtoul (pc, NULL, 16);
1361         if (errno)
1362                 return FALSE;
1363         *c = (guint32) tmp;
1364
1365         return TRUE;
1366 }
1367
1368 NMMatchSpecMatchType
1369 nm_match_spec_s390_subchannels (const GSList *specs, const char *subchannels)
1370 {
1371         const GSList *iter;
1372         guint32 a = 0, b = 0, c = 0;
1373         guint32 spec_a = 0, spec_b = 0, spec_c = 0;
1374         NMMatchSpecMatchType match = NM_MATCH_SPEC_NO_MATCH;
1375
1376         g_return_val_if_fail (subchannels != NULL, NM_MATCH_SPEC_NO_MATCH);
1377
1378         if (!specs)
1379                 return NM_MATCH_SPEC_NO_MATCH;
1380
1381         if (!parse_subchannels (subchannels, &a, &b, &c))
1382                 return NM_MATCH_SPEC_NO_MATCH;
1383
1384         for (iter = specs; iter; iter = g_slist_next (iter)) {
1385                 const char *spec_str = iter->data;
1386                 gboolean except;
1387
1388                 if (!spec_str || !*spec_str)
1389                         continue;
1390
1391                 spec_str = _match_except (spec_str, &except);
1392
1393                 if (!g_ascii_strncasecmp (spec_str, SUBCHAN_TAG, NM_STRLEN (SUBCHAN_TAG))) {
1394                         spec_str += NM_STRLEN (SUBCHAN_TAG);
1395                         if (parse_subchannels (spec_str, &spec_a, &spec_b, &spec_c)) {
1396                                 if (a == spec_a && b == spec_b && c == spec_c) {
1397                                         if (except)
1398                                                 return NM_MATCH_SPEC_NEG_MATCH;
1399                                         match = NM_MATCH_SPEC_MATCH;
1400                                 }
1401                         }
1402                 }
1403         }
1404         return match;
1405 }
1406
1407 static gboolean
1408 _match_config_nm_version (const char *str, const char *tag, guint cur_nm_version)
1409 {
1410         gs_free char *s_ver = NULL;
1411         gs_strfreev char **s_ver_tokens = NULL;
1412         gint v_maj = -1, v_min = -1, v_mic = -1;
1413         guint c_maj = -1, c_min = -1, c_mic = -1;
1414         guint n_tokens;
1415
1416         s_ver = g_strdup (str);
1417         g_strstrip (s_ver);
1418
1419         /* Let's be strict with the accepted format here. No funny stuff!! */
1420
1421         if (s_ver[strspn (s_ver, ".0123456789")] != '\0')
1422                 return FALSE;
1423
1424         s_ver_tokens = g_strsplit (s_ver, ".", -1);
1425         n_tokens = g_strv_length (s_ver_tokens);
1426         if (n_tokens == 0 || n_tokens > 3)
1427                 return FALSE;
1428
1429         v_maj = _nm_utils_ascii_str_to_int64 (s_ver_tokens[0], 10, 0, 0xFFFF, -1);
1430         if (v_maj < 0)
1431                 return FALSE;
1432         if (n_tokens >= 2) {
1433                 v_min = _nm_utils_ascii_str_to_int64 (s_ver_tokens[1], 10, 0, 0xFF, -1);
1434                 if (v_min < 0)
1435                         return FALSE;
1436         }
1437         if (n_tokens >= 3) {
1438                 v_mic = _nm_utils_ascii_str_to_int64 (s_ver_tokens[2], 10, 0, 0xFF, -1);
1439                 if (v_mic < 0)
1440                         return FALSE;
1441         }
1442
1443         nm_decode_version (cur_nm_version, &c_maj, &c_min, &c_mic);
1444
1445 #define CHECK_AND_RETURN_FALSE(cur, val, tag, is_last_digit) \
1446         G_STMT_START { \
1447                 if (!strcmp (tag, MATCH_TAG_CONFIG_NM_VERSION_MIN)) { \
1448                         if (cur < val) \
1449                                 return FALSE; \
1450                 } else if (!strcmp (tag, MATCH_TAG_CONFIG_NM_VERSION_MAX)) { \
1451                         if (cur > val) \
1452                                 return FALSE; \
1453                 } else { \
1454                         if (cur != val) \
1455                                 return FALSE; \
1456                 } \
1457                 if (!(is_last_digit)) { \
1458                         if (cur != val) \
1459                                 return FALSE; \
1460                 } \
1461         } G_STMT_END
1462         if (v_mic >= 0)
1463                 CHECK_AND_RETURN_FALSE (c_mic, v_mic, tag, TRUE);
1464         if (v_min >= 0)
1465                 CHECK_AND_RETURN_FALSE (c_min, v_min, tag, v_mic < 0);
1466         CHECK_AND_RETURN_FALSE (c_maj, v_maj, tag, v_min < 0);
1467         return TRUE;
1468 }
1469
1470 NMMatchSpecMatchType
1471 nm_match_spec_match_config (const GSList *specs, guint cur_nm_version, const char *env)
1472 {
1473         const GSList *iter;
1474         NMMatchSpecMatchType match = NM_MATCH_SPEC_NO_MATCH;
1475
1476         if (!specs)
1477                 return NM_MATCH_SPEC_NO_MATCH;
1478
1479         for (iter = specs; iter; iter = g_slist_next (iter)) {
1480                 const char *spec_str = iter->data;
1481                 gboolean except;
1482                 gboolean v_match;
1483
1484                 if (!spec_str || !*spec_str)
1485                         continue;
1486
1487                 spec_str = _match_except (spec_str, &except);
1488
1489                 if (_spec_has_prefix (&spec_str, MATCH_TAG_CONFIG_NM_VERSION))
1490                         v_match = _match_config_nm_version (spec_str, MATCH_TAG_CONFIG_NM_VERSION, cur_nm_version);
1491                 else if (_spec_has_prefix (&spec_str, MATCH_TAG_CONFIG_NM_VERSION_MIN))
1492                         v_match = _match_config_nm_version (spec_str, MATCH_TAG_CONFIG_NM_VERSION_MIN, cur_nm_version);
1493                 else if (_spec_has_prefix (&spec_str, MATCH_TAG_CONFIG_NM_VERSION_MAX))
1494                         v_match = _match_config_nm_version (spec_str, MATCH_TAG_CONFIG_NM_VERSION_MAX, cur_nm_version);
1495                 else if (_spec_has_prefix (&spec_str, MATCH_TAG_CONFIG_ENV))
1496                         v_match = env && env[0] && !strcmp (spec_str, env);
1497                 else
1498                         continue;
1499
1500                 if (v_match) {
1501                         if (except)
1502                                 return NM_MATCH_SPEC_NEG_MATCH;
1503                         match = NM_MATCH_SPEC_MATCH;
1504                 }
1505         }
1506         return match;
1507 }
1508
1509 /**
1510  * nm_match_spec_split:
1511  * @value: the string of device specs
1512  *
1513  * Splits the specs from the string and returns them as individual
1514  * entires in a #GSList.
1515  *
1516  * It does not validate any specs, it basically just does a special
1517  * strsplit with ',' or ';' as separators and supporting '\\' as
1518  * escape character.
1519  *
1520  * Leading and trailing spaces of each entry are removed. But the user
1521  * can preserve them by specifying "\\s has 2 leading" or "has 2 trailing \\s".
1522  *
1523  * Specs can have a qualifier like "interface-name:". We still don't strip
1524  * any whitespace after the colon, so "interface-name: X" matches an interface
1525  * named " X".
1526  *
1527  * Returns: (transfer full): the list of device specs.
1528  */
1529 GSList *
1530 nm_match_spec_split (const char *value)
1531 {
1532         char *string_value, *p, *q0, *q;
1533         GSList *pieces = NULL;
1534         int trailing_ws;
1535
1536         if (!value || !*value)
1537                 return NULL;
1538
1539         /* Copied from glibs g_key_file_parse_value_as_string() function
1540          * and adjusted. */
1541
1542         string_value = g_new (gchar, strlen (value) + 1);
1543
1544         p = (gchar *) value;
1545
1546         /* skip over leading whitespace */
1547         while (g_ascii_isspace (*p))
1548                 p++;
1549
1550         q0 = q = string_value;
1551         trailing_ws = 0;
1552         while (*p) {
1553                 if (*p == '\\') {
1554                         p++;
1555
1556                         switch (*p) {
1557                         case 's':
1558                                 *q = ' ';
1559                                 break;
1560                         case 'n':
1561                                 *q = '\n';
1562                                 break;
1563                         case 't':
1564                                 *q = '\t';
1565                                 break;
1566                         case 'r':
1567                                 *q = '\r';
1568                                 break;
1569                         case '\\':
1570                                 *q = '\\';
1571                                 break;
1572                         case '\0':
1573                                 break;
1574                         default:
1575                                 if (NM_IN_SET (*p, ',', ';'))
1576                                         *q = *p;
1577                                 else {
1578                                         *q++ = '\\';
1579                                         *q = *p;
1580                                 }
1581                                 break;
1582                         }
1583                         if (*p == '\0')
1584                                 break;
1585                         p++;
1586                         trailing_ws = 0;
1587                 } else {
1588                         *q = *p;
1589                         if (*p == '\0')
1590                                 break;
1591                         if (g_ascii_isspace (*p)) {
1592                                 trailing_ws++;
1593                                 p++;
1594                         } else if (NM_IN_SET (*p, ',', ';')) {
1595                                 if (q0 < q - trailing_ws)
1596                                         pieces = g_slist_prepend (pieces, g_strndup (q0, (q - q0) - trailing_ws));
1597                                 q0 = q + 1;
1598                                 p++;
1599                                 trailing_ws = 0;
1600                                 while (g_ascii_isspace (*p))
1601                                         p++;
1602                         } else
1603                                 p++;
1604                 }
1605                 q++;
1606         }
1607
1608         *q = '\0';
1609         if (q0 < q - trailing_ws)
1610                 pieces = g_slist_prepend (pieces, g_strndup (q0, (q - q0) - trailing_ws));
1611         g_free (string_value);
1612         return g_slist_reverse (pieces);
1613 }
1614
1615 /**
1616  * nm_match_spec_join:
1617  * @specs: the device specs to join
1618  *
1619  * This is based on g_key_file_parse_string_as_value(), analog to
1620  * nm_match_spec_split() which is based on g_key_file_parse_value_as_string().
1621  *
1622  * Returns: (transfer full): a joined list of device specs that can be
1623  *   split again with nm_match_spec_split(). Note that
1624  *   nm_match_spec_split (nm_match_spec_join (specs)) yields the original
1625  *   result (which is not true the other way around because there are multiple
1626  *   ways to encode the same joined specs string).
1627  */
1628 char *
1629 nm_match_spec_join (GSList *specs)
1630 {
1631         const char *p;
1632         GString *str;
1633
1634         str = g_string_new ("");
1635
1636         for (; specs; specs = specs->next) {
1637                 p = specs->data;
1638
1639                 if (!p || !*p)
1640                         continue;
1641
1642                 if (str->len > 0)
1643                         g_string_append_c (str, ',');
1644
1645                 /* escape leading whitespace */
1646                 switch (*p) {
1647                 case ' ':
1648                         g_string_append (str, "\\s");
1649                         p++;
1650                         break;
1651                 case '\t':
1652                         g_string_append (str, "\\t");
1653                         p++;
1654                         break;
1655                 }
1656
1657                 for (; *p; p++) {
1658                         switch (*p) {
1659                         case '\n':
1660                                 g_string_append (str, "\\n");
1661                                 break;
1662                         case '\r':
1663                                 g_string_append (str, "\\r");
1664                                 break;
1665                         case '\\':
1666                                 g_string_append (str, "\\\\");
1667                                 break;
1668                         case ',':
1669                                 g_string_append (str, "\\,");
1670                                 break;
1671                         case ';':
1672                                 g_string_append (str, "\\;");
1673                                 break;
1674                         default:
1675                                 g_string_append_c (str, *p);
1676                                 break;
1677                         }
1678                 }
1679
1680                 /* escape trailing whitespaces */
1681                 switch (str->str[str->len - 1]) {
1682                 case ' ':
1683                         g_string_overwrite (str, str->len - 1, "\\s");
1684                         break;
1685                 case '\t':
1686                         g_string_overwrite (str, str->len - 1, "\\t");
1687                         break;
1688                 }
1689         }
1690
1691         return g_string_free (str, FALSE);
1692 }
1693
1694 /*****************************************************************************/
1695
1696 char _nm_utils_to_string_buffer[];
1697
1698 void
1699 nm_utils_to_string_buffer_init (char **buf, gsize *len)
1700 {
1701         if (!*buf) {
1702                 *buf = _nm_utils_to_string_buffer;
1703                 *len = sizeof (_nm_utils_to_string_buffer);
1704         }
1705 }
1706
1707 gboolean
1708 nm_utils_to_string_buffer_init_null (gconstpointer obj, char **buf, gsize *len)
1709 {
1710         nm_utils_to_string_buffer_init (buf, len);
1711         if (!obj) {
1712                 g_strlcpy (*buf, "(null)", *len);
1713                 return FALSE;
1714         }
1715         return TRUE;
1716 }
1717
1718 void
1719 nm_utils_strbuf_append_c (char **buf, gsize *len, char c)
1720 {
1721         switch (*len) {
1722         case 0:
1723                 return;
1724         case 1:
1725                 (*buf)[0] = '\0';
1726                 *len = 0;
1727                 (*buf)++;
1728                 return;
1729         default:
1730                 (*buf)[0] = c;
1731                 (*buf)[1] = '\0';
1732                 (*len)--;
1733                 (*buf)++;
1734                 return;
1735         }
1736 }
1737
1738 void
1739 nm_utils_strbuf_append_str (char **buf, gsize *len, const char *str)
1740 {
1741         gsize src_len;
1742
1743         switch (*len) {
1744         case 0:
1745                 return;
1746         case 1:
1747                 if (!str || !*str) {
1748                         (*buf)[0] = '\0';
1749                         return;
1750                 }
1751                 (*buf)[0] = '\0';
1752                 *len = 0;
1753                 (*buf)++;
1754                 return;
1755         default:
1756                 if (!str || !*str) {
1757                         (*buf)[0] = '\0';
1758                         return;
1759                 }
1760                 src_len = g_strlcpy (*buf, str, *len);
1761                 if (src_len >= *len) {
1762                         *buf = &(*buf)[*len];
1763                         *len = 0;
1764                 } else {
1765                         *buf = &(*buf)[src_len];
1766                         *len -= src_len;
1767                 }
1768                 return;
1769         }
1770 }
1771
1772 void
1773 nm_utils_strbuf_append (char **buf, gsize *len, const char *format, ...)
1774 {
1775         char *p = *buf;
1776         va_list args;
1777         gint retval;
1778
1779         if (*len == 0)
1780                 return;
1781
1782         va_start (args, format);
1783         retval = g_vsnprintf (p, *len, format, args);
1784         va_end (args);
1785
1786         if (retval >= *len) {
1787                 *buf = &p[*len];
1788                 *len = 0;
1789         } else {
1790                 *buf = &p[retval];
1791                 *len -= retval;
1792         }
1793 }
1794
1795 const char *
1796 nm_utils_flags2str (const NMUtilsFlags2StrDesc *descs,
1797                     gsize n_descs,
1798                     unsigned flags,
1799                     char *buf,
1800                     gsize len)
1801 {
1802         gsize i;
1803         char *p;
1804
1805 #if NM_MORE_ASSERTS > 10
1806         nm_assert (descs);
1807         nm_assert (n_descs > 0);
1808         for (i = 0; i < n_descs; i++) {
1809                 gsize j;
1810
1811                 nm_assert (descs[i].flag && nm_utils_is_power_of_two (descs[i].flag));
1812                 nm_assert (descs[i].name && descs[i].name[0]);
1813                 for (j = 0; j < i; j++)
1814                         nm_assert (descs[j].flag != descs[i].flag);
1815         }
1816 #endif
1817
1818         nm_utils_to_string_buffer_init (&buf, &len);
1819
1820         if (!len)
1821                 return buf;
1822
1823         buf[0] = '\0';
1824         if (!flags) {
1825                 return buf;
1826         }
1827
1828         p = buf;
1829         for (i = 0; flags && i < n_descs; i++) {
1830                 if (NM_FLAGS_HAS (flags, descs[i].flag)) {
1831                         flags &= ~descs[i].flag;
1832
1833                         if (buf[0] != '\0')
1834                                 nm_utils_strbuf_append_c (&p, &len, ',');
1835                         nm_utils_strbuf_append_str (&p, &len, descs[i].name);
1836                 }
1837         }
1838         if (flags) {
1839                 if (buf[0] != '\0')
1840                         nm_utils_strbuf_append_c (&p, &len, ',');
1841                 nm_utils_strbuf_append (&p, &len, "0x%x", flags);
1842         }
1843         return buf;
1844 };
1845
1846 /*****************************************************************************/
1847
1848 char *
1849 nm_utils_new_vlan_name (const char *parent_iface, guint32 vlan_id)
1850 {
1851         guint id_len;
1852         gsize parent_len;
1853         char *ifname;
1854
1855         g_return_val_if_fail (parent_iface && *parent_iface, NULL);
1856
1857         if (vlan_id < 10)
1858                 id_len = 2;
1859         else if (vlan_id < 100)
1860                 id_len = 3;
1861         else if (vlan_id < 1000)
1862                 id_len = 4;
1863         else {
1864                 g_return_val_if_fail (vlan_id < 4095, NULL);
1865                 id_len = 5;
1866         }
1867
1868         ifname = g_new (char, IFNAMSIZ);
1869
1870         parent_len = strlen (parent_iface);
1871         parent_len = MIN (parent_len, IFNAMSIZ - 1 - id_len);
1872         memcpy (ifname, parent_iface, parent_len);
1873         g_snprintf (&ifname[parent_len], IFNAMSIZ - parent_len, ".%u", vlan_id);
1874
1875         return ifname;
1876 }
1877
1878 /**
1879  * nm_utils_read_resolv_conf_nameservers():
1880  * @rc_contents: contents of a resolv.conf; or %NULL to read /etc/resolv.conf
1881  *
1882  * Reads all nameservers out of @rc_contents or /etc/resolv.conf and returns
1883  * them.
1884  *
1885  * Returns: a #GPtrArray of 'char *' elements of each nameserver line from
1886  * @contents or resolv.conf
1887  */
1888 GPtrArray *
1889 nm_utils_read_resolv_conf_nameservers (const char *rc_contents)
1890 {
1891         GPtrArray *nameservers = NULL;
1892         char *contents = NULL;
1893         char **lines, **iter;
1894         char *p;
1895
1896         if (rc_contents)
1897                 contents = g_strdup (rc_contents);
1898         else {
1899                 if (!g_file_get_contents (_PATH_RESCONF, &contents, NULL, NULL))
1900                         return NULL;
1901         }
1902
1903         nameservers = g_ptr_array_new_full (3, g_free);
1904
1905         lines = g_strsplit_set (contents, "\r\n", -1);
1906         for (iter = lines; *iter; iter++) {
1907                 if (!g_str_has_prefix (*iter, "nameserver"))
1908                         continue;
1909                 p = *iter + strlen ("nameserver");
1910                 if (!g_ascii_isspace (*p++))
1911                         continue;
1912                 /* Skip intermediate whitespace */
1913                 while (g_ascii_isspace (*p))
1914                         p++;
1915                 g_strchomp (p);
1916
1917                 g_ptr_array_add (nameservers, g_strdup (p));
1918         }
1919         g_strfreev (lines);
1920         g_free (contents);
1921
1922         return nameservers;
1923 }
1924
1925 /**
1926  * nm_utils_read_resolv_conf_dns_options():
1927  * @rc_contents: contents of a resolv.conf; or %NULL to read /etc/resolv.conf
1928  *
1929  * Reads all dns options out of @rc_contents or /etc/resolv.conf and returns
1930  * them.
1931  *
1932  * Returns: a #GPtrArray of 'char *' elements of each option
1933  */
1934 GPtrArray *
1935 nm_utils_read_resolv_conf_dns_options (const char *rc_contents)
1936 {
1937         GPtrArray *options = NULL;
1938         char *contents = NULL;
1939         char **lines, **line_iter;
1940         char **tokens, **token_iter;
1941         char *p;
1942
1943         if (rc_contents)
1944                 contents = g_strdup (rc_contents);
1945         else {
1946                 if (!g_file_get_contents (_PATH_RESCONF, &contents, NULL, NULL))
1947                         return NULL;
1948         }
1949
1950         options = g_ptr_array_new_full (3, g_free);
1951
1952         lines = g_strsplit_set (contents, "\r\n", -1);
1953         for (line_iter = lines; *line_iter; line_iter++) {
1954                 if (!g_str_has_prefix (*line_iter, "options"))
1955                         continue;
1956                 p = *line_iter + strlen ("options");
1957                 if (!g_ascii_isspace (*p++))
1958                         continue;
1959
1960                 tokens = g_strsplit (p, " ", 0);
1961                 for (token_iter = tokens; token_iter && *token_iter; token_iter++) {
1962                         g_strstrip (*token_iter);
1963                         if (!*token_iter[0])
1964                                 continue;
1965                         g_ptr_array_add (options, g_strdup (*token_iter));
1966                 }
1967                 g_strfreev (tokens);
1968         }
1969         g_strfreev (lines);
1970         g_free (contents);
1971
1972         return options;
1973 }
1974
1975 int
1976 nm_utils_cmp_connection_by_autoconnect_priority (NMConnection **a, NMConnection **b)
1977 {
1978         NMSettingConnection *a_s_con, *b_s_con;
1979         gboolean a_ac, b_ac;
1980         gint a_ap, b_ap;
1981
1982         a_s_con = nm_connection_get_setting_connection (*a);
1983         b_s_con = nm_connection_get_setting_connection (*b);
1984
1985         a_ac = !!nm_setting_connection_get_autoconnect (a_s_con);
1986         b_ac = !!nm_setting_connection_get_autoconnect (b_s_con);
1987         if (a_ac != b_ac)
1988                 return ((int) b_ac) - ((int) a_ac);
1989         if (!a_ac)
1990                 return 0;
1991
1992         a_ap = nm_setting_connection_get_autoconnect_priority (a_s_con);
1993         b_ap = nm_setting_connection_get_autoconnect_priority (b_s_con);
1994         if (a_ap != b_ap)
1995                 return (a_ap > b_ap) ? -1 : 1;
1996
1997         return 0;
1998 }
1999
2000 /**************************************************************************/
2001
2002 static gint64 monotonic_timestamp_offset_sec;
2003 static int monotonic_timestamp_clock_mode = 0;
2004
2005 static void
2006 monotonic_timestamp_get (struct timespec *tp)
2007 {
2008         int clock_mode = 0;
2009         int err = 0;
2010
2011         switch (monotonic_timestamp_clock_mode) {
2012         case 0:
2013                 /* the clock is not yet initialized (first run) */
2014                 err = clock_gettime (CLOCK_BOOTTIME, tp);
2015                 if (err == -1 && errno == EINVAL) {
2016                         clock_mode = 2;
2017                         err = clock_gettime (CLOCK_MONOTONIC, tp);
2018                 } else
2019                         clock_mode = 1;
2020                 break;
2021         case 1:
2022                 /* default, return CLOCK_BOOTTIME */
2023                 err = clock_gettime (CLOCK_BOOTTIME, tp);
2024                 break;
2025         case 2:
2026                 /* fallback, return CLOCK_MONOTONIC. Kernels prior to 2.6.39
2027                  * don't support CLOCK_BOOTTIME. */
2028                 err = clock_gettime (CLOCK_MONOTONIC, tp);
2029                 break;
2030         }
2031
2032         g_assert (err == 0); (void)err;
2033         g_assert (tp->tv_nsec >= 0 && tp->tv_nsec < NM_UTILS_NS_PER_SECOND);
2034
2035         if (G_LIKELY (clock_mode == 0))
2036                 return;
2037
2038         /* Calculate an offset for the time stamp.
2039          *
2040          * We always want positive values, because then we can initialize
2041          * a timestamp with 0 and be sure, that it will be less then any
2042          * value nm_utils_get_monotonic_timestamp_*() might return.
2043          * For this to be true also for nm_utils_get_monotonic_timestamp_s() at
2044          * early boot, we have to shift the timestamp to start counting at
2045          * least from 1 second onward.
2046          *
2047          * Another advantage of shifting is, that this way we make use of the whole 31 bit
2048          * range of signed int, before the time stamp for nm_utils_get_monotonic_timestamp_s()
2049          * wraps (~68 years).
2050          **/
2051         monotonic_timestamp_offset_sec = (- ((gint64) tp->tv_sec)) + 1;
2052         monotonic_timestamp_clock_mode = clock_mode;
2053
2054         if (nm_logging_enabled (LOGL_DEBUG, LOGD_CORE)) {
2055                 time_t now = time (NULL);
2056                 struct tm tm;
2057                 char s[255];
2058
2059                 strftime (s, sizeof (s), "%Y-%m-%d %H:%M:%S", localtime_r (&now, &tm));
2060                 nm_log_dbg (LOGD_CORE, "monotonic timestamp started counting 1.%09ld seconds ago with "
2061                                        "an offset of %lld.0 seconds to %s (local time is %s)",
2062                                        tp->tv_nsec, (long long) -monotonic_timestamp_offset_sec,
2063                                        clock_mode == 1 ? "CLOCK_BOOTTIME" : "CLOCK_MONOTONIC", s);
2064         }
2065 }
2066
2067 /**
2068  * nm_utils_get_monotonic_timestamp_ns:
2069  *
2070  * Returns: a monotonically increasing time stamp in nanoseconds,
2071  * starting at an unspecified offset. See clock_gettime(), %CLOCK_BOOTTIME.
2072  *
2073  * The returned value will start counting at an undefined point
2074  * in the past and will always be positive.
2075  *
2076  * All the nm_utils_get_monotonic_timestamp_*s functions return the same
2077  * timestamp but in different scales (nsec, usec, msec, sec).
2078  **/
2079 gint64
2080 nm_utils_get_monotonic_timestamp_ns (void)
2081 {
2082         struct timespec tp = { 0 };
2083
2084         monotonic_timestamp_get (&tp);
2085
2086         /* Although the result will always be positive, we return a signed
2087          * integer, which makes it easier to calculate time differences (when
2088          * you want to subtract signed values).
2089          **/
2090         return (((gint64) tp.tv_sec) + monotonic_timestamp_offset_sec) * NM_UTILS_NS_PER_SECOND +
2091                tp.tv_nsec;
2092 }
2093
2094 /**
2095  * nm_utils_get_monotonic_timestamp_us:
2096  *
2097  * Returns: a monotonically increasing time stamp in microseconds,
2098  * starting at an unspecified offset. See clock_gettime(), %CLOCK_BOOTTIME.
2099  *
2100  * The returned value will start counting at an undefined point
2101  * in the past and will always be positive.
2102  *
2103  * All the nm_utils_get_monotonic_timestamp_*s functions return the same
2104  * timestamp but in different scales (nsec, usec, msec, sec).
2105  **/
2106 gint64
2107 nm_utils_get_monotonic_timestamp_us (void)
2108 {
2109         struct timespec tp = { 0 };
2110
2111         monotonic_timestamp_get (&tp);
2112
2113         /* Although the result will always be positive, we return a signed
2114          * integer, which makes it easier to calculate time differences (when
2115          * you want to subtract signed values).
2116          **/
2117         return (((gint64) tp.tv_sec) + monotonic_timestamp_offset_sec) * ((gint64) G_USEC_PER_SEC) +
2118                (tp.tv_nsec / (NM_UTILS_NS_PER_SECOND/G_USEC_PER_SEC));
2119 }
2120
2121 /**
2122  * nm_utils_get_monotonic_timestamp_ms:
2123  *
2124  * Returns: a monotonically increasing time stamp in milliseconds,
2125  * starting at an unspecified offset. See clock_gettime(), %CLOCK_BOOTTIME.
2126  *
2127  * The returned value will start counting at an undefined point
2128  * in the past and will always be positive.
2129  *
2130  * All the nm_utils_get_monotonic_timestamp_*s functions return the same
2131  * timestamp but in different scales (nsec, usec, msec, sec).
2132  **/
2133 gint64
2134 nm_utils_get_monotonic_timestamp_ms (void)
2135 {
2136         struct timespec tp = { 0 };
2137
2138         monotonic_timestamp_get (&tp);
2139
2140         /* Although the result will always be positive, we return a signed
2141          * integer, which makes it easier to calculate time differences (when
2142          * you want to subtract signed values).
2143          **/
2144         return (((gint64) tp.tv_sec) + monotonic_timestamp_offset_sec) * ((gint64) 1000) +
2145                (tp.tv_nsec / (NM_UTILS_NS_PER_SECOND/1000));
2146 }
2147
2148 /**
2149  * nm_utils_get_monotonic_timestamp_s:
2150  *
2151  * Returns: nm_utils_get_monotonic_timestamp_ms() in seconds (throwing
2152  * away sub second parts). The returned value will always be positive.
2153  *
2154  * This value wraps after roughly 68 years which should be fine for any
2155  * practical purpose.
2156  *
2157  * All the nm_utils_get_monotonic_timestamp_*s functions return the same
2158  * timestamp but in different scales (nsec, usec, msec, sec).
2159  **/
2160 gint32
2161 nm_utils_get_monotonic_timestamp_s (void)
2162 {
2163         struct timespec tp = { 0 };
2164
2165         monotonic_timestamp_get (&tp);
2166         return (((gint64) tp.tv_sec) + monotonic_timestamp_offset_sec);
2167 }
2168
2169 typedef struct
2170 {
2171         const char *name;
2172         NMSetting *setting;
2173         NMSetting *diff_base_setting;
2174         GHashTable *setting_diff;
2175 } LogConnectionSettingData;
2176
2177 typedef struct
2178 {
2179         const char *item_name;
2180         NMSettingDiffResult diff_result;
2181 } LogConnectionSettingItem;
2182
2183 static gint
2184 _log_connection_sort_hashes_fcn (gconstpointer a, gconstpointer b)
2185 {
2186         const LogConnectionSettingData *v1 = a;
2187         const LogConnectionSettingData *v2 = b;
2188         guint32 p1, p2;
2189         NMSetting *s1, *s2;
2190
2191         s1 = v1->setting ? v1->setting : v1->diff_base_setting;
2192         s2 = v2->setting ? v2->setting : v2->diff_base_setting;
2193
2194         g_assert (s1 && s2);
2195
2196         p1 = _nm_setting_get_setting_priority (s1);
2197         p2 = _nm_setting_get_setting_priority (s2);
2198
2199         if (p1 != p2)
2200                 return p1 > p2 ? 1 : -1;
2201
2202         return strcmp (v1->name, v2->name);
2203 }
2204
2205 static GArray *
2206 _log_connection_sort_hashes (NMConnection *connection, NMConnection *diff_base, GHashTable *connection_diff)
2207 {
2208         GHashTableIter iter;
2209         GArray *sorted_hashes;
2210         LogConnectionSettingData setting_data;
2211
2212         sorted_hashes = g_array_sized_new (TRUE, FALSE, sizeof (LogConnectionSettingData), g_hash_table_size (connection_diff));
2213
2214         g_hash_table_iter_init (&iter, connection_diff);
2215         while (g_hash_table_iter_next (&iter, (gpointer) &setting_data.name, (gpointer) &setting_data.setting_diff)) {
2216                 setting_data.setting = nm_connection_get_setting_by_name (connection, setting_data.name);
2217                 setting_data.diff_base_setting = diff_base ? nm_connection_get_setting_by_name (diff_base, setting_data.name) : NULL;
2218                 g_assert (setting_data.setting || setting_data.diff_base_setting);
2219                 g_array_append_val (sorted_hashes, setting_data);
2220         }
2221
2222         g_array_sort (sorted_hashes, _log_connection_sort_hashes_fcn);
2223         return sorted_hashes;
2224 }
2225
2226 static gint
2227 _log_connection_sort_names_fcn (gconstpointer a, gconstpointer b)
2228 {
2229         const LogConnectionSettingItem *v1 = a;
2230         const LogConnectionSettingItem *v2 = b;
2231
2232         /* we want to first show the items, that disappeared, then the one that changed and
2233          * then the ones that were added. */
2234
2235         if ((v1->diff_result & NM_SETTING_DIFF_RESULT_IN_A) != (v2->diff_result & NM_SETTING_DIFF_RESULT_IN_A))
2236                 return (v1->diff_result & NM_SETTING_DIFF_RESULT_IN_A) ? -1 : 1;
2237         if ((v1->diff_result & NM_SETTING_DIFF_RESULT_IN_B) != (v2->diff_result & NM_SETTING_DIFF_RESULT_IN_B))
2238                 return (v1->diff_result & NM_SETTING_DIFF_RESULT_IN_B) ? 1 : -1;
2239         return strcmp (v1->item_name, v2->item_name);
2240 }
2241
2242 static char *
2243 _log_connection_get_property (NMSetting *setting, const char *name)
2244 {
2245         GValue val = G_VALUE_INIT;
2246         char *s;
2247
2248         g_return_val_if_fail (setting, NULL);
2249
2250         if (   !NM_IS_SETTING_VPN (setting)
2251             && nm_setting_get_secret_flags (setting, name, NULL, NULL))
2252                 return g_strdup ("****");
2253
2254         if (!_nm_setting_get_property (setting, name, &val))
2255                 g_return_val_if_reached (FALSE);
2256
2257         if (G_VALUE_HOLDS_STRING (&val)) {
2258                 const char *val_s;
2259
2260                 val_s = g_value_get_string (&val);
2261                 if (!val_s) {
2262                         /* for NULL, we want to return the unquoted string "NULL". */
2263                         s = g_strdup ("NULL");
2264                 } else {
2265                         char *escaped = g_strescape (val_s, "'");
2266
2267                         s = g_strdup_printf ("'%s'", escaped);
2268                         g_free (escaped);
2269                 }
2270         } else {
2271                 s = g_strdup_value_contents (&val);
2272                 if (s == NULL)
2273                         s = g_strdup ("NULL");
2274                 else {
2275                         char *escaped = g_strescape (s, "'");
2276
2277                         g_free (s);
2278                         s = escaped;
2279                 }
2280         }
2281         g_value_unset(&val);
2282         return s;
2283 }
2284
2285 static void
2286 _log_connection_sort_names (LogConnectionSettingData *setting_data, GArray *sorted_names)
2287 {
2288         GHashTableIter iter;
2289         LogConnectionSettingItem item;
2290         gpointer p;
2291
2292         g_array_set_size (sorted_names, 0);
2293
2294         g_hash_table_iter_init (&iter, setting_data->setting_diff);
2295         while (g_hash_table_iter_next (&iter, (gpointer) &item.item_name, &p)) {
2296                 item.diff_result = GPOINTER_TO_UINT (p);
2297                 g_array_append_val (sorted_names, item);
2298         }
2299
2300         g_array_sort (sorted_names, _log_connection_sort_names_fcn);
2301 }
2302
2303 void
2304 nm_utils_log_connection_diff (NMConnection *connection, NMConnection *diff_base, guint32 level, guint64 domain, const char *name, const char *prefix)
2305 {
2306         GHashTable *connection_diff = NULL;
2307         GArray *sorted_hashes;
2308         GArray *sorted_names = NULL;
2309         int i, j;
2310         gboolean connection_diff_are_same;
2311         gboolean print_header = TRUE;
2312         gboolean print_setting_header;
2313         GString *str1;
2314
2315         g_return_if_fail (NM_IS_CONNECTION (connection));
2316         g_return_if_fail (!diff_base || (NM_IS_CONNECTION (diff_base) && diff_base != connection));
2317
2318         /* For VPN setting types, this is broken, because we cannot (generically) print the content of data/secrets. Bummer... */
2319
2320         if (!nm_logging_enabled (level, domain))
2321                 return;
2322
2323         if (!prefix)
2324                 prefix = "";
2325         if (!name)
2326                 name = "";
2327
2328         connection_diff_are_same = nm_connection_diff (connection, diff_base, NM_SETTING_COMPARE_FLAG_EXACT | NM_SETTING_COMPARE_FLAG_DIFF_RESULT_NO_DEFAULT, &connection_diff);
2329         if (connection_diff_are_same) {
2330                 if (diff_base)
2331                         nm_log (level, domain, "%sconnection '%s' (%p/%s and %p/%s): no difference", prefix, name, connection, G_OBJECT_TYPE_NAME (connection), diff_base, G_OBJECT_TYPE_NAME (diff_base));
2332                 else
2333                         nm_log (level, domain, "%sconnection '%s' (%p/%s): no properties set", prefix, name, connection, G_OBJECT_TYPE_NAME (connection));
2334                 g_assert (!connection_diff);
2335                 return;
2336         }
2337
2338         /* FIXME: it doesn't nicely show the content of NMSettingVpn, becuase nm_connection_diff() does not
2339          * expand the hash values. */
2340
2341         sorted_hashes = _log_connection_sort_hashes (connection, diff_base, connection_diff);
2342         if (sorted_hashes->len <= 0)
2343                 goto out;
2344
2345         sorted_names = g_array_new (FALSE, FALSE, sizeof (LogConnectionSettingItem));
2346         str1 = g_string_new (NULL);
2347
2348         for (i = 0; i < sorted_hashes->len; i++) {
2349                 LogConnectionSettingData *setting_data = &g_array_index (sorted_hashes, LogConnectionSettingData, i);
2350
2351                 _log_connection_sort_names (setting_data, sorted_names);
2352                 print_setting_header = TRUE;
2353                 for (j = 0; j < sorted_names->len; j++) {
2354                         char *str_conn, *str_diff;
2355                         LogConnectionSettingItem *item = &g_array_index (sorted_names, LogConnectionSettingItem, j);
2356
2357                         str_conn = (item->diff_result & NM_SETTING_DIFF_RESULT_IN_A)
2358                                    ? _log_connection_get_property (setting_data->setting, item->item_name)
2359                                    : NULL;
2360                         str_diff = (item->diff_result & NM_SETTING_DIFF_RESULT_IN_B)
2361                                    ? _log_connection_get_property (setting_data->diff_base_setting, item->item_name)
2362                                    : NULL;
2363
2364                         if (print_header) {
2365                                 GError *err_verify = NULL;
2366                                 const char *path = nm_connection_get_path (connection);
2367
2368                                 if (diff_base) {
2369                                         nm_log (level, domain, "%sconnection '%s' (%p/%s < %p/%s)%s%s%s:", prefix, name, connection, G_OBJECT_TYPE_NAME (connection), diff_base, G_OBJECT_TYPE_NAME (diff_base),
2370                                                 NM_PRINT_FMT_QUOTED (path, " [", path, "]", ""));
2371                                 } else {
2372                                         nm_log (level, domain, "%sconnection '%s' (%p/%s):%s%s%s", prefix, name, connection, G_OBJECT_TYPE_NAME (connection),
2373                                                 NM_PRINT_FMT_QUOTED (path, " [", path, "]", ""));
2374                                 }
2375                                 print_header = FALSE;
2376
2377                                 if (!nm_connection_verify (connection, &err_verify)) {
2378                                         nm_log (level, domain, "%sconnection %p does not verify: %s", prefix, connection, err_verify->message);
2379                                         g_clear_error (&err_verify);
2380                                 }
2381                         }
2382 #define _NM_LOG_ALIGN "-25"
2383                         if (print_setting_header) {
2384                                 if (diff_base) {
2385                                         if (setting_data->setting && setting_data->diff_base_setting)
2386                                                 g_string_printf (str1, "%p < %p", setting_data->setting, setting_data->diff_base_setting);
2387                                         else if (setting_data->diff_base_setting)
2388                                                 g_string_printf (str1, "*missing* < %p", setting_data->diff_base_setting);
2389                                         else
2390                                                 g_string_printf (str1, "%p < *missing*", setting_data->setting);
2391                                         nm_log (level, domain, "%s%"_NM_LOG_ALIGN"s [ %s ]", prefix, setting_data->name, str1->str);
2392                                 } else
2393                                         nm_log (level, domain, "%s%"_NM_LOG_ALIGN"s [ %p ]", prefix, setting_data->name, setting_data->setting);
2394                                 print_setting_header = FALSE;
2395                         }
2396                         g_string_printf (str1, "%s.%s", setting_data->name, item->item_name);
2397                         switch (item->diff_result & (NM_SETTING_DIFF_RESULT_IN_A | NM_SETTING_DIFF_RESULT_IN_B)) {
2398                                 case NM_SETTING_DIFF_RESULT_IN_B:
2399                                         nm_log (level, domain, "%s%"_NM_LOG_ALIGN"s < %s", prefix, str1->str, str_diff ? str_diff : "NULL");
2400                                         break;
2401                                 case NM_SETTING_DIFF_RESULT_IN_A:
2402                                         nm_log (level, domain, "%s%"_NM_LOG_ALIGN"s = %s", prefix, str1->str, str_conn ? str_conn : "NULL");
2403                                         break;
2404                                 default:
2405                                         nm_log (level, domain, "%s%"_NM_LOG_ALIGN"s = %s < %s", prefix, str1->str, str_conn ? str_conn : "NULL", str_diff ? str_diff : "NULL");
2406                                         break;
2407 #undef _NM_LOG_ALIGN
2408                         }
2409                         g_free (str_conn);
2410                         g_free (str_diff);
2411                 }
2412         }
2413
2414         g_array_free (sorted_names, TRUE);
2415         g_string_free (str1, TRUE);
2416 out:
2417         g_hash_table_destroy (connection_diff);
2418         g_array_free (sorted_hashes, TRUE);
2419 }
2420
2421 /**
2422  * nm_utils_monotonic_timestamp_as_boottime:
2423  * @timestamp: the monotonic-timestamp that should be converted into CLOCK_BOOTTIME.
2424  * @timestamp_ns_per_tick: How many nano seconds make one unit of @timestamp? E.g. if
2425  * @timestamp is in unit seconds, pass %NM_UTILS_NS_PER_SECOND; @timestamp in nano
2426  * seconds, pass 1; @timestamp in milli seconds, pass %NM_UTILS_NS_PER_SECOND/1000; etc.
2427  *
2428  * Returns: the monotonic-timestamp as CLOCK_BOOTTIME, as returned by clock_gettime().
2429  * The unit is the same as the passed in @timestamp basd on @timestamp_ns_per_tick.
2430  * E.g. if you passed @timestamp in as seconds, it will return boottime in seconds.
2431  * If @timestamp is a non-positive, it returns -1. Note that a (valid) monotonic-timestamp
2432  * is always positive.
2433  *
2434  * On older kernels that don't support CLOCK_BOOTTIME, the returned time is instead CLOCK_MONOTONIC.
2435  **/
2436 gint64
2437 nm_utils_monotonic_timestamp_as_boottime (gint64 timestamp, gint64 timestamp_ns_per_tick)
2438 {
2439         gint64 offset;
2440
2441         /* only support ns-per-tick being a multiple of 10. */
2442         g_return_val_if_fail (timestamp_ns_per_tick == 1
2443                               || (timestamp_ns_per_tick > 0 &&
2444                                   timestamp_ns_per_tick <= NM_UTILS_NS_PER_SECOND &&
2445                                   timestamp_ns_per_tick % 10 == 0),
2446                               -1);
2447
2448         /* Check that the timestamp is in a valid range. */
2449         g_return_val_if_fail (timestamp >= 0, -1);
2450
2451         /* if the caller didn't yet ever fetch a monotonic-timestamp, he cannot pass any meaningful
2452          * value (because he has no idea what these timestamps would be). That would be a bug. */
2453         g_return_val_if_fail (monotonic_timestamp_clock_mode != 0, -1);
2454
2455         /* calculate the offset of monotonic-timestamp to boottime. offset_s is <= 1. */
2456         offset = monotonic_timestamp_offset_sec * (NM_UTILS_NS_PER_SECOND / timestamp_ns_per_tick);
2457
2458         /* check for overflow. */
2459         g_return_val_if_fail (offset > 0 || timestamp < G_MAXINT64 + offset, G_MAXINT64);
2460
2461         return timestamp - offset;
2462 }
2463
2464
2465 #define IPV6_PROPERTY_DIR "/proc/sys/net/ipv6/conf/"
2466 #define IPV4_PROPERTY_DIR "/proc/sys/net/ipv4/conf/"
2467 G_STATIC_ASSERT (sizeof (IPV4_PROPERTY_DIR) == sizeof (IPV6_PROPERTY_DIR));
2468
2469 static const char *
2470 _get_property_path (const char *ifname,
2471                     const char *property,
2472                     gboolean ipv6)
2473 {
2474         static char path[sizeof (IPV6_PROPERTY_DIR) + IFNAMSIZ + 32];
2475         int len;
2476
2477         ifname = NM_ASSERT_VALID_PATH_COMPONENT (ifname);
2478         property = NM_ASSERT_VALID_PATH_COMPONENT (property);
2479
2480         len = g_snprintf (path,
2481                           sizeof (path),
2482                           "%s%s/%s",
2483                           ipv6 ? IPV6_PROPERTY_DIR : IPV4_PROPERTY_DIR,
2484                           ifname,
2485                           property);
2486         g_assert (len < sizeof (path) - 1);
2487
2488         return path;
2489 }
2490
2491 /**
2492  * nm_utils_ip6_property_path:
2493  * @ifname: an interface name
2494  * @property: a property name
2495  *
2496  * Returns the path to IPv6 property @property on @ifname. Note that
2497  * this uses a static buffer.
2498  */
2499 const char *
2500 nm_utils_ip6_property_path (const char *ifname, const char *property)
2501 {
2502         return _get_property_path (ifname, property, TRUE);
2503 }
2504
2505 /**
2506  * nm_utils_ip4_property_path:
2507  * @ifname: an interface name
2508  * @property: a property name
2509  *
2510  * Returns the path to IPv4 property @property on @ifname. Note that
2511  * this uses a static buffer.
2512  */
2513 const char *
2514 nm_utils_ip4_property_path (const char *ifname, const char *property)
2515 {
2516         return _get_property_path (ifname, property, FALSE);
2517 }
2518
2519 gboolean
2520 nm_utils_is_valid_path_component (const char *name)
2521 {
2522         const char *n;
2523
2524         if (name == NULL || name[0] == '\0')
2525                 return FALSE;
2526
2527         if (name[0] == '.') {
2528                 if (name[1] == '\0')
2529                         return FALSE;
2530                 if (name[1] == '.' && name[2] == '\0')
2531                         return FALSE;
2532         }
2533         n = name;
2534         do {
2535                 if (*n == '/')
2536                         return FALSE;
2537         } while (*(++n) != '\0');
2538
2539         return TRUE;
2540 }
2541
2542 const char *
2543 NM_ASSERT_VALID_PATH_COMPONENT (const char *name)
2544 {
2545         if (G_LIKELY (nm_utils_is_valid_path_component (name)))
2546                 return name;
2547
2548         nm_log_err (LOGD_CORE, "Failed asserting path component: %s%s%s",
2549                     NM_PRINT_FMT_QUOTED (name, "\"", name, "\"", "(null)"));
2550         g_error ("FATAL: Failed asserting path component: %s%s%s",
2551                  NM_PRINT_FMT_QUOTED (name, "\"", name, "\"", "(null)"));
2552         g_assert_not_reached ();
2553 }
2554
2555 gboolean
2556 nm_utils_is_specific_hostname (const char *name)
2557 {
2558         if (!name)
2559                 return FALSE;
2560         if (   strcmp (name, "(none)")
2561             && strcmp (name, "localhost")
2562             && strcmp (name, "localhost6")
2563             && strcmp (name, "localhost.localdomain")
2564             && strcmp (name, "localhost6.localdomain6"))
2565                 return TRUE;
2566         return FALSE;
2567 }
2568
2569 /******************************************************************/
2570
2571 /* Returns the "u" (universal/local) bit value for a Modified EUI-64 */
2572 static gboolean
2573 get_gre_eui64_u_bit (guint32 addr)
2574 {
2575         static const struct {
2576                 guint32 mask;
2577                 guint32 result;
2578         } items[] = {
2579                 { 0xff000000 }, { 0x7f000000 },  /* IPv4 loopback */
2580                 { 0xf0000000 }, { 0xe0000000 },  /* IPv4 multicast */
2581                 { 0xffffff00 }, { 0xe0000000 },  /* IPv4 local multicast */
2582                 { 0xffffffff }, { INADDR_BROADCAST },  /* limited broadcast */
2583                 { 0xff000000 }, { 0x00000000 },  /* zero net */
2584                 { 0xff000000 }, { 0x0a000000 },  /* private 10 (RFC3330) */
2585                 { 0xfff00000 }, { 0xac100000 },  /* private 172 */
2586                 { 0xffff0000 }, { 0xc0a80000 },  /* private 192 */
2587                 { 0xffff0000 }, { 0xa9fe0000 },  /* IPv4 link-local */
2588                 { 0xffffff00 }, { 0xc0586300 },  /* anycast 6-to-4 */
2589                 { 0xffffff00 }, { 0xc0000200 },  /* test 192 */
2590                 { 0xfffe0000 }, { 0xc6120000 },  /* test 198 */
2591         };
2592         guint i;
2593
2594         for (i = 0; i < G_N_ELEMENTS (items); i++) {
2595                 if ((addr & htonl (items[i].mask)) == htonl (items[i].result))
2596                         return 0x00; /* "local" scope */
2597         }
2598         return 0x02; /* "universal" scope */
2599 }
2600
2601 /**
2602  * nm_utils_get_ipv6_interface_identifier:
2603  * @link_type: the hardware link type
2604  * @hwaddr: the hardware address of the interface
2605  * @hwaddr_len: the length (in bytes) of @hwaddr
2606  * @dev_id: the device identifier, if any
2607  * @out_iid: on success, filled with the interface identifier; on failure
2608  * zeroed out
2609  *
2610  * Constructs an interface identifier in "Modified EUI-64" format which is
2611  * suitable for constructing IPv6 addresses.  Note that the identifier is
2612  * not obscured in any way (eg, RFC3041).
2613  *
2614  * Returns: %TRUE if the interface identifier could be constructed, %FALSE if
2615  * if could not be constructed.
2616  */
2617 gboolean
2618 nm_utils_get_ipv6_interface_identifier (NMLinkType link_type,
2619                                         const guint8 *hwaddr,
2620                                         guint hwaddr_len,
2621                                         guint dev_id,
2622                                         NMUtilsIPv6IfaceId *out_iid)
2623 {
2624         guint32 addr;
2625
2626         g_return_val_if_fail (hwaddr != NULL, FALSE);
2627         g_return_val_if_fail (hwaddr_len > 0, FALSE);
2628         g_return_val_if_fail (out_iid != NULL, FALSE);
2629
2630         out_iid->id = 0;
2631
2632         switch (link_type) {
2633         case NM_LINK_TYPE_INFINIBAND:
2634                 /* Use the port GUID per http://tools.ietf.org/html/rfc4391#section-8,
2635                  * making sure to set the 'u' bit to 1.  The GUID is the lower 64 bits
2636                  * of the IPoIB interface's hardware address.
2637                  */
2638                 g_return_val_if_fail (hwaddr_len == INFINIBAND_ALEN, FALSE);
2639                 memcpy (out_iid->id_u8, hwaddr + INFINIBAND_ALEN - 8, 8);
2640                 out_iid->id_u8[0] |= 0x02;
2641                 return TRUE;
2642         case NM_LINK_TYPE_GRE:
2643         case NM_LINK_TYPE_GRETAP:
2644                 /* Hardware address is the network-endian IPv4 address */
2645                 g_return_val_if_fail (hwaddr_len == 4, FALSE);
2646                 addr = * (guint32 *) hwaddr;
2647                 out_iid->id_u8[0] = get_gre_eui64_u_bit (addr);
2648                 out_iid->id_u8[1] = 0x00;
2649                 out_iid->id_u8[2] = 0x5E;
2650                 out_iid->id_u8[3] = 0xFE;
2651                 memcpy (out_iid->id_u8 + 4, &addr, 4);
2652                 return TRUE;
2653         default:
2654                 if (hwaddr_len == ETH_ALEN) {
2655                         /* Translate 48-bit MAC address to a 64-bit Modified EUI-64.  See
2656                          * http://tools.ietf.org/html/rfc4291#appendix-A and the Linux
2657                          * kernel's net/ipv6/addrconf.c::ipv6_generate_eui64() function.
2658                          */
2659                         out_iid->id_u8[0] = hwaddr[0];
2660                         out_iid->id_u8[1] = hwaddr[1];
2661                         out_iid->id_u8[2] = hwaddr[2];
2662                         if (dev_id) {
2663                                 out_iid->id_u8[3] = (dev_id >> 8) & 0xff;
2664                                 out_iid->id_u8[4] = dev_id & 0xff;
2665                         } else {
2666                                 out_iid->id_u8[0] ^= 0x02;
2667                                 out_iid->id_u8[3] = 0xff;
2668                                 out_iid->id_u8[4] = 0xfe;
2669                         }
2670                         out_iid->id_u8[5] = hwaddr[3];
2671                         out_iid->id_u8[6] = hwaddr[4];
2672                         out_iid->id_u8[7] = hwaddr[5];
2673                         return TRUE;
2674                 }
2675                 break;
2676         }
2677         return FALSE;
2678 }
2679 void
2680 nm_utils_ipv6_addr_set_interface_identfier (struct in6_addr *addr,
2681                                             const NMUtilsIPv6IfaceId iid)
2682 {
2683         memcpy (addr->s6_addr + 8, &iid.id_u8, 8);
2684 }
2685
2686 void
2687 nm_utils_ipv6_interface_identfier_get_from_addr (NMUtilsIPv6IfaceId *iid,
2688                                                  const struct in6_addr *addr)
2689 {
2690         memcpy (iid, addr->s6_addr + 8, 8);
2691 }
2692
2693 static gboolean
2694 _set_stable_privacy (struct in6_addr *addr,
2695                      const char *ifname,
2696                      const char *uuid,
2697                      guint dad_counter,
2698                      gchar *secret_key,
2699                      gsize key_len,
2700                      GError **error)
2701 {
2702         GChecksum *sum;
2703         guint8 digest[32];
2704         guint32 tmp[2];
2705         gsize len = sizeof (digest);
2706
2707         g_return_val_if_fail (key_len, FALSE);
2708
2709         /* Documentation suggests that this can fail.
2710          * Maybe in case of a missing algorithm in crypto library? */
2711         sum = g_checksum_new (G_CHECKSUM_SHA256);
2712         if (!sum) {
2713                 g_set_error_literal (error, NM_UTILS_ERROR, NM_UTILS_ERROR_UNKNOWN,
2714                                      "Can't create a SHA256 hash");
2715                 return FALSE;
2716         }
2717
2718         key_len = MIN (key_len, G_MAXUINT32);
2719
2720         g_checksum_update (sum, addr->s6_addr, 8);
2721         g_checksum_update (sum, (const guchar *) ifname, strlen (ifname) + 1);
2722         if (!uuid)
2723                 uuid = "";
2724         g_checksum_update (sum, (const guchar *) uuid, strlen (uuid) + 1);
2725         tmp[0] = htonl (dad_counter);
2726         tmp[1] = htonl (key_len);
2727         g_checksum_update (sum, (const guchar *) tmp, sizeof (tmp));
2728         g_checksum_update (sum, (const guchar *) secret_key, key_len);
2729
2730         g_checksum_get_digest (sum, digest, &len);
2731         g_checksum_free (sum);
2732
2733         g_return_val_if_fail (len == 32, FALSE);
2734
2735         memcpy (addr->s6_addr + 8, &digest[0], 8);
2736
2737         return TRUE;
2738 }
2739
2740 #define RFC7217_IDGEN_RETRIES 3
2741 /**
2742  * nm_utils_ipv6_addr_set_stable_privacy:
2743  *
2744  * Extend the address prefix with an interface identifier using the
2745  * RFC 7217 Stable Privacy mechanism.
2746  *
2747  * Returns: %TRUE on success, %FALSE if the address could not be generated.
2748  */
2749 gboolean
2750 nm_utils_ipv6_addr_set_stable_privacy (struct in6_addr *addr,
2751                                        const char *ifname,
2752                                        const char *uuid,
2753                                        guint dad_counter,
2754                                        GError **error)
2755 {
2756         gchar *secret_key = NULL;
2757         gsize key_len = 0;
2758         gboolean success = FALSE;
2759
2760         if (dad_counter >= RFC7217_IDGEN_RETRIES) {
2761                 g_set_error_literal (error, NM_UTILS_ERROR, NM_UTILS_ERROR_UNKNOWN,
2762                                      "Too many DAD collisions");
2763                 return FALSE;
2764         }
2765
2766         /* Let's try to load a saved secret key first. */
2767         if (g_file_get_contents (NMSTATEDIR "/secret_key", &secret_key, &key_len, NULL)) {
2768                 if (key_len < 16) {
2769                         g_set_error_literal (error, NM_UTILS_ERROR, NM_UTILS_ERROR_UNKNOWN,
2770                                              "Key is too short to be usable");
2771                         key_len = 0;
2772                 }
2773         } else {
2774                 int urandom = open ("/dev/urandom", O_RDONLY);
2775                 mode_t key_mask;
2776
2777                 if (urandom == -1) {
2778                         g_set_error (error, NM_UTILS_ERROR, NM_UTILS_ERROR_UNKNOWN,
2779                                      "Can't open /dev/urandom: %s", strerror (errno));
2780                         return FALSE;
2781                 }
2782
2783                 /* RFC7217 mandates the key SHOULD be at least 128 bits.
2784                  * Let's use twice as much. */
2785                 key_len = 32;
2786                 secret_key = g_malloc (key_len);
2787
2788                 key_mask = umask (0077);
2789                 if (read (urandom, secret_key, key_len) == key_len) {
2790                         if (!g_file_set_contents (NMSTATEDIR "/secret_key", secret_key, key_len, error)) {
2791                                 g_prefix_error (error, "Can't write " NMSTATEDIR "/secret_key");
2792                                 key_len = 0;
2793                         }
2794                 } else {
2795                         g_set_error_literal (error, NM_UTILS_ERROR, NM_UTILS_ERROR_UNKNOWN,
2796                                              "Could not obtain a secret");
2797                         key_len = 0;
2798                 }
2799                 umask (key_mask);
2800                 close (urandom);
2801         }
2802
2803         if (key_len) {
2804                 success = _set_stable_privacy (addr, ifname, uuid, dad_counter,
2805                                                secret_key, key_len, error);
2806         }
2807
2808         g_free (secret_key);
2809         return success;
2810 }
2811
2812 /**
2813  * nm_utils_setpgid:
2814  * @unused: unused
2815  *
2816  * This can be passed as a child setup function to the g_spawn*() family
2817  * of functions, to ensure that the child is in its own process group
2818  * (and thus, in some situations, will not be killed when NetworkManager
2819  * is killed).
2820  */
2821 void
2822 nm_utils_setpgid (gpointer unused G_GNUC_UNUSED)
2823 {
2824         pid_t pid;
2825
2826         pid = getpid ();
2827         setpgid (pid, pid);
2828 }
2829
2830 /**
2831  * nm_utils_g_value_set_strv:
2832  * @value: a #GValue, initialized to store a #G_TYPE_STRV
2833  * @strings: a #GPtrArray of strings
2834  *
2835  * Converts @strings to a #GStrv and stores it in @value.
2836  */
2837 void
2838 nm_utils_g_value_set_strv (GValue *value, GPtrArray *strings)
2839 {
2840         char **strv;
2841         int i;
2842
2843         strv = g_new (char *, strings->len + 1);
2844         for (i = 0; i < strings->len; i++)
2845                 strv[i] = g_strdup (strings->pdata[i]);
2846         strv[i] = NULL;
2847
2848         g_value_take_boxed (value, strv);
2849 }
2850
2851 /*****************************************************************************/
2852
2853 static gboolean
2854 debug_key_matches (const gchar *key,
2855                    const gchar *token,
2856                    guint        length)
2857 {
2858         /* may not call GLib functions: see note in g_parse_debug_string() */
2859         for (; length; length--, key++, token++) {
2860                 char k = (*key   == '_') ? '-' : g_ascii_tolower (*key  );
2861                 char t = (*token == '_') ? '-' : g_ascii_tolower (*token);
2862
2863                 if (k != t)
2864                         return FALSE;
2865         }
2866
2867         return *key == '\0';
2868 }
2869
2870 /**
2871  * nm_utils_parse_debug_string:
2872  * @string: the string to parse
2873  * @keys: the debug keys
2874  * @nkeys: number of entires in @keys
2875  *
2876  * Similar to g_parse_debug_string(), but does not special
2877  * case "help" or "all".
2878  *
2879  * Returns: the flags
2880  */
2881 guint
2882 nm_utils_parse_debug_string (const char *string,
2883                              const GDebugKey *keys,
2884                              guint nkeys)
2885 {
2886         guint i;
2887         guint result = 0;
2888         const char *q;
2889
2890         if (string == NULL)
2891                 return 0;
2892
2893         while (*string) {
2894                 q = strpbrk (string, ":;, \t");
2895                 if (!q)
2896                         q = string + strlen (string);
2897
2898                 for (i = 0; i < nkeys; i++) {
2899                         if (debug_key_matches (keys[i].key, string, q - string))
2900                                 result |= keys[i].value;
2901                 }
2902
2903                 string = q;
2904                 if (*string)
2905                         string++;
2906         }
2907
2908         return result;
2909 }
2910
2911 /*****************************************************************************/
2912
2913 void
2914 nm_utils_ifname_cpy (char *dst, const char *name)
2915 {
2916         g_return_if_fail (dst);
2917         g_return_if_fail (name && name[0]);
2918
2919         nm_assert (nm_utils_iface_valid_name (name));
2920
2921         if (g_strlcpy (dst, name, IFNAMSIZ) >= IFNAMSIZ)
2922                 g_return_if_reached ();
2923 }
2924
2925 /*****************************************************************************/
2926
2927 #define IPV4LL_NETWORK (htonl (0xA9FE0000L))
2928 #define IPV4LL_NETMASK (htonl (0xFFFF0000L))
2929
2930 gboolean
2931 nm_utils_ip4_address_is_link_local (in_addr_t addr)
2932 {
2933         return (addr & IPV4LL_NETMASK) == IPV4LL_NETWORK;
2934 }
2935
2936 /*****************************************************************************/
2937
2938 /**
2939  * Takes a pair @timestamp and @duration, and returns the remaining duration based
2940  * on the new timestamp @now.
2941  */
2942 guint32
2943 nm_utils_lifetime_rebase_relative_time_on_now (guint32 timestamp,
2944                                                guint32 duration,
2945                                                gint32 now)
2946 {
2947         gint64 t;
2948
2949         nm_assert (now >= 0);
2950
2951         if (duration == NM_PLATFORM_LIFETIME_PERMANENT)
2952                 return NM_PLATFORM_LIFETIME_PERMANENT;
2953
2954         if (timestamp == 0) {
2955                 /* if the @timestamp is zero, assume it was just left unset and that the relative
2956                  * @duration starts counting from @now. This is convenient to construct an address
2957                  * and print it in nm_platform_ip4_address_to_string().
2958                  *
2959                  * In general it does not make sense to set the @duration without anchoring at
2960                  * @timestamp because you don't know the absolute expiration time when looking
2961                  * at the address at a later moment. */
2962                 timestamp = now;
2963         }
2964
2965         /* For timestamp > now, just accept it and calculate the expected(?) result. */
2966         t = (gint64) timestamp + (gint64) duration - (gint64) now;
2967
2968         if (t <= 0)
2969                 return 0;
2970         if (t >= NM_PLATFORM_LIFETIME_PERMANENT)
2971                 return NM_PLATFORM_LIFETIME_PERMANENT - 1;
2972         return t;
2973 }
2974
2975 gboolean
2976 nm_utils_lifetime_get (guint32 timestamp,
2977                        guint32 lifetime,
2978                        guint32 preferred,
2979                        gint32 now,
2980                        guint32 *out_lifetime,
2981                        guint32 *out_preferred)
2982 {
2983         guint32 t_lifetime, t_preferred;
2984
2985         nm_assert (now >= 0);
2986
2987         if (lifetime == 0) {
2988                 *out_lifetime = NM_PLATFORM_LIFETIME_PERMANENT;
2989                 *out_preferred = NM_PLATFORM_LIFETIME_PERMANENT;
2990
2991                 /* We treat lifetime==0 as permanent addresses to allow easy creation of such addresses
2992                  * (without requiring to set the lifetime fields to NM_PLATFORM_LIFETIME_PERMANENT).
2993                  * In that case we also expect that the other fields (timestamp and preferred) are left unset. */
2994                 g_return_val_if_fail (timestamp == 0 && preferred == 0, TRUE);
2995         } else {
2996                 if (now <= 0)
2997                         now = nm_utils_get_monotonic_timestamp_s ();
2998                 t_lifetime = nm_utils_lifetime_rebase_relative_time_on_now (timestamp, lifetime, now);
2999                 if (!t_lifetime) {
3000                         *out_lifetime = 0;
3001                         *out_preferred = 0;
3002                         return FALSE;
3003                 }
3004                 t_preferred = nm_utils_lifetime_rebase_relative_time_on_now (timestamp, preferred, now);
3005
3006                 *out_lifetime = t_lifetime;
3007                 *out_preferred = MIN (t_preferred, t_lifetime);
3008
3009                 /* Assert that non-permanent addresses have a (positive) @timestamp. nm_utils_lifetime_rebase_relative_time_on_now()
3010                  * treats addresses with timestamp 0 as *now*. Addresses passed to _address_get_lifetime() always
3011                  * should have a valid @timestamp, otherwise on every re-sync, their lifetime will be extended anew.
3012                  */
3013                 g_return_val_if_fail (   timestamp != 0
3014                                       || (   lifetime  == NM_PLATFORM_LIFETIME_PERMANENT
3015                                           && preferred == NM_PLATFORM_LIFETIME_PERMANENT), TRUE);
3016                 g_return_val_if_fail (t_preferred <= t_lifetime, TRUE);
3017         }
3018         return TRUE;
3019 }
3020