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