diff --git a/configure.ac b/configure.ac index f945c6fad6..780f007af0 100644 --- a/configure.ac +++ b/configure.ac @@ -86,6 +86,9 @@ AC_SUBST(nmdatadir, '${datadir}'/$PACKAGE, [NetworkManager shared data directory AC_SUBST(nmstatedir, '${localstatedir}'/lib/$PACKAGE, [NetworkManager persistent state directory]) AC_SUBST(nmrundir, '${runstatedir}'/$PACKAGE, [NetworkManager runtime state directory]) +AC_GNU_SOURCE +AC_CHECK_FUNCS([__secure_getenv secure_getenv]) + # Alternative configuration plugins AC_ARG_ENABLE(config-plugin-ibft, AS_HELP_STRING([--enable-config-plugin-ibft], [enable ibft configuration plugin])) AC_ARG_ENABLE(ifcfg-rh, AS_HELP_STRING([--enable-ifcfg-rh], [enable ifcfg-rh configuration plugin (Fedora/RHEL)])) diff --git a/src/Makefile.am b/src/Makefile.am index 34483b5ba8..f7f2e73b6e 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -156,6 +156,7 @@ libsystemd_nm_la_SOURCES = \ systemd/src/libsystemd-network/sd-ipv4acd.c \ systemd/src/libsystemd-network/sd-ipv4ll.c \ systemd/src/libsystemd-network/sd-lldp.c \ + systemd/src/libsystemd/sd-event/sd-event.c \ systemd/src/libsystemd/sd-id128/sd-id128.c \ systemd/src/shared/dns-domain.c \ systemd/src/shared/dns-domain.h \ diff --git a/src/devices/tests/test-lldp.c b/src/devices/tests/test-lldp.c index 80ba725b05..2af46ab976 100644 --- a/src/devices/tests/test-lldp.c +++ b/src/devices/tests/test-lldp.c @@ -27,6 +27,7 @@ #include #include "nm-lldp-listener.h" +#include "nm-sd-adapt.h" #include "lldp.h" @@ -394,6 +395,7 @@ test_recv (TestRecvFixture *fixture, gconstpointer user_data) gsize i_frames; gulong notify_id; GError *error = NULL; + guint sd_id; listener = nm_lldp_listener_new (); g_assert (listener != NULL); @@ -403,6 +405,7 @@ test_recv (TestRecvFixture *fixture, gconstpointer user_data) notify_id = g_signal_connect (listener, "notify::" NM_LLDP_LISTENER_NEIGHBORS, (GCallback) lldp_neighbors_changed, &info); loop = g_main_loop_new (NULL, FALSE); + sd_id = nm_sd_event_attach_default (); for (i_frames = 0; i_frames < data->frames_len; i_frames++) { const TestRecvFrame *f = data->frames[i_frames]; @@ -419,6 +422,7 @@ test_recv (TestRecvFixture *fixture, gconstpointer user_data) data->check (loop, listener); + nm_clear_g_source (&sd_id); g_clear_pointer (&loop, g_main_loop_unref); } diff --git a/src/main.c b/src/main.c index 0f074b012d..9bbc299e58 100644 --- a/src/main.c +++ b/src/main.c @@ -50,6 +50,7 @@ #include "nm-auth-manager.h" #include "nm-core-internal.h" #include "nm-exported-object.h" +#include "nm-sd-adapt.h" #if !defined(NM_DIST_VERSION) # define NM_DIST_VERSION VERSION @@ -271,6 +272,7 @@ main (int argc, char *argv[]) gboolean wrote_pidfile = FALSE; char *bad_domains = NULL; NMConfigCmdLineOptions *config_cli; + guint sd_id = 0; nm_g_type_init (); @@ -474,8 +476,11 @@ main (int argc, char *argv[]) success = TRUE; - if (configure_and_quit == FALSE) + if (configure_and_quit == FALSE) { + sd_id = nm_sd_event_attach_default (); + g_main_loop_run (main_loop); + } done: nm_exported_object_class_set_quitting (); @@ -486,5 +491,8 @@ done: unlink (global_opt.pidfile); nm_log_info (LOGD_CORE, "exiting (%s)", success ? "success" : "error"); + + nm_clear_g_source (&sd_id); + exit (success ? 0 : 1); } diff --git a/src/nm-iface-helper.c b/src/nm-iface-helper.c index 225464c094..247b771d49 100644 --- a/src/nm-iface-helper.c +++ b/src/nm-iface-helper.c @@ -44,6 +44,7 @@ extern unsigned int if_nametoindex (const char *__ifname); #include "nm-lndp-rdisc.h" #include "nm-utils.h" #include "nm-setting-ip6-config.h" +#include "nm-sd-adapt.h" #if !defined(NM_DIST_VERSION) # define NM_DIST_VERSION VERSION @@ -345,6 +346,7 @@ main (int argc, char *argv[]) size_t hwaddr_len = 0; gconstpointer tmp; gs_free NMUtilsIPv6IfaceId *iid = NULL; + guint sd_id; nm_g_type_init (); @@ -494,6 +496,8 @@ main (int argc, char *argv[]) nm_rdisc_start (rdisc); } + sd_id = nm_sd_event_attach_default (); + g_main_loop_run (main_loop); g_clear_pointer (&hwaddr, g_byte_array_unref); @@ -502,6 +506,8 @@ main (int argc, char *argv[]) unlink (pidfile); nm_log_info (LOGD_CORE, "exiting"); + + nm_clear_g_source (&sd_id); exit (0); } diff --git a/src/systemd/nm-sd-adapt.c b/src/systemd/nm-sd-adapt.c index 40d52e76b4..ec276dcf9f 100644 --- a/src/systemd/nm-sd-adapt.c +++ b/src/systemd/nm-sd-adapt.c @@ -20,233 +20,126 @@ #include "nm-sd-adapt.h" -#include -#include - #include "sd-event.h" #include "fd-util.h" -#include "time-util.h" -struct sd_event_source { - guint refcount; - guint id; - gpointer user_data; - - GIOChannel *channel; - - union { - struct { - sd_event_io_handler_t cb; - } io; - struct { - sd_event_time_handler_t cb; - uint64_t usec; - } time; - }; -}; - -static struct sd_event_source * -source_new (void) -{ - struct sd_event_source *source; - - source = g_slice_new0 (struct sd_event_source); - source->refcount = 1; - return source; -} +/*****************************************************************************/ int -sd_event_source_set_priority (sd_event_source *s, int64_t priority) -{ - return 0; -} - -int -sd_event_source_set_enabled (sd_event_source *s, int m) -{ - /* TODO */ - g_return_val_if_reached (-EINVAL); -} - -int -sd_event_source_set_time (sd_event_source *s, uint64_t usec) -{ - /* TODO */ - g_return_val_if_reached (-EINVAL); -} - -sd_event_source* -sd_event_source_unref (sd_event_source *s) -{ - - if (!s) - return NULL; - - g_return_val_if_fail (s->refcount, NULL); - - s->refcount--; - if (s->refcount == 0) { - if (s->id) - g_source_remove (s->id); - if (s->channel) { - /* Don't shut down the channel since systemd will soon close - * the file descriptor itself, which would cause -EBADF. - */ - g_io_channel_unref (s->channel); - } - g_slice_free (struct sd_event_source, s); - } - return NULL; -} - -int -sd_event_source_set_description(sd_event_source *s, const char *description) -{ - if (!s) - return -EINVAL; - - g_source_set_name_by_id (s->id, description); - return 0; -} - -static gboolean -io_ready (GIOChannel *channel, GIOCondition condition, struct sd_event_source *source) -{ - int r, revents = 0; - gboolean result; - - if (condition & G_IO_IN) - revents |= EPOLLIN; - if (condition & G_IO_OUT) - revents |= EPOLLOUT; - if (condition & G_IO_PRI) - revents |= EPOLLPRI; - if (condition & G_IO_ERR) - revents |= EPOLLERR; - if (condition & G_IO_HUP) - revents |= EPOLLHUP; - - source->refcount++; - - r = source->io.cb (source, g_io_channel_unix_get_fd (channel), revents, source->user_data); - if (r < 0 || source->refcount <= 1) { - source->id = 0; - result = G_SOURCE_REMOVE; - } else - result = G_SOURCE_CONTINUE; - - sd_event_source_unref (source); - - return result; -} - -int -sd_event_add_io (sd_event *e, sd_event_source **s, int fd, uint32_t events, sd_event_io_handler_t callback, void *userdata) -{ - struct sd_event_source *source; - GIOChannel *channel; - GIOCondition condition = 0; - - /* systemd supports floating sd_event_source by omitting the @s argument. - * We don't have such users and don't implement floating references. */ - g_return_val_if_fail (s, -EINVAL); - - channel = g_io_channel_unix_new (fd); - if (!channel) - return -EINVAL; - - source = source_new (); - source->io.cb = callback; - source->user_data = userdata; - source->channel = channel; - - if (events & EPOLLIN) - condition |= G_IO_IN; - if (events & EPOLLOUT) - condition |= G_IO_OUT; - if (events & EPOLLPRI) - condition |= G_IO_PRI; - if (events & EPOLLERR) - condition |= G_IO_ERR; - if (events & EPOLLHUP) - condition |= G_IO_HUP; - - g_io_channel_set_encoding (source->channel, NULL, NULL); - g_io_channel_set_buffered (source->channel, FALSE); - source->id = g_io_add_watch (source->channel, condition, (GIOFunc) io_ready, source); - - *s = source; - return 0; -} - -static gboolean -time_ready (struct sd_event_source *source) -{ - source->refcount++; - - source->time.cb (source, source->time.usec, source->user_data); - source->id = 0; - - sd_event_source_unref (source); - - return G_SOURCE_REMOVE; -} - -int -sd_event_add_time(sd_event *e, sd_event_source **s, clockid_t clock, uint64_t usec, uint64_t accuracy, sd_event_time_handler_t callback, void *userdata) -{ - struct sd_event_source *source; - uint64_t n = now (clock); - - /* systemd supports floating sd_event_source by omitting the @s argument. - * We don't have such users and don't implement floating references. */ - g_return_val_if_fail (s, -EINVAL); - - source = source_new (); - source->time.cb = callback; - source->user_data = userdata; - source->time.usec = usec; - - if (usec > 1000) - usec = n < usec - 1000 ? usec - n : 1000; - source->id = g_timeout_add (usec / 1000, (GSourceFunc) time_ready, source); - - *s = source; - return 0; -} - -/* sd_event is basically a GMainContext; but since we only - * ever use the default context, nothing to do here. - */ - -int -sd_event_default (sd_event **e) -{ - *e = GUINT_TO_POINTER (1); - return 0; -} - -sd_event* -sd_event_ref (sd_event *e) -{ - return e; -} - -sd_event* -sd_event_unref (sd_event *e) -{ - return NULL; -} - -int -sd_event_now (sd_event *e, clockid_t clock, uint64_t *usec) -{ - *usec = now (clock); - return 0; -} - -int asynchronous_close(int fd) { - safe_close(fd); +asynchronous_close (int fd) { + safe_close (fd); return -1; } +/***************************************************************************** + * Integrating sd_event into glib. Taken and adjusted from + * https://www.freedesktop.org/software/systemd/man/sd_event_get_fd.html + *****************************************************************************/ + +typedef struct SDEventSource { + GSource source; + GPollFD pollfd; + sd_event *event; + guint *default_source_id; +} SDEventSource; + +static gboolean +event_prepare (GSource *source, gint *timeout_) +{ + return sd_event_prepare (((SDEventSource *) source)->event) > 0; +} + +static gboolean +event_check (GSource *source) +{ + return sd_event_wait (((SDEventSource *) source)->event, 0) > 0; +} + +static gboolean +event_dispatch (GSource *source, GSourceFunc callback, gpointer user_data) +{ + return sd_event_dispatch (((SDEventSource *)source)->event) > 0; +} + +static void +event_finalize (GSource *source) +{ + SDEventSource *s; + + s = (SDEventSource *) source; + sd_event_unref (s->event); + if (s->default_source_id) + *s->default_source_id = 0; +} + +static SDEventSource * +event_create_source (sd_event *event, guint *default_source_id) +{ + static GSourceFuncs event_funcs = { + .prepare = event_prepare, + .check = event_check, + .dispatch = event_dispatch, + .finalize = event_finalize, + }; + SDEventSource *source; + + g_return_val_if_fail (event, NULL); + + source = (SDEventSource *) g_source_new (&event_funcs, sizeof (SDEventSource)); + + source->event = sd_event_ref (event); + source->pollfd.fd = sd_event_get_fd (event); + source->pollfd.events = G_IO_IN | G_IO_HUP | G_IO_ERR; + source->default_source_id = default_source_id; + + g_source_add_poll ((GSource *) source, &source->pollfd); + + return source; +} + +static guint +event_attach (sd_event *event, GMainContext *context) +{ + SDEventSource *source; + guint id; + int r; + sd_event *e = event; + guint *p_default_source_id = NULL; + + if (!e) { + static guint default_source_id = 0; + + if (default_source_id) { + /* The default event cannot be registered multiple times. */ + g_return_val_if_reached (0); + } + + r = sd_event_default (&e); + if (r < 0) + g_return_val_if_reached (0); + + p_default_source_id = &default_source_id; + } + + source = event_create_source (e, p_default_source_id); + id = g_source_attach ((GSource *) source, context); + g_source_unref ((GSource *) source); + + + if (!event) { + *p_default_source_id = id; + sd_event_unref (e); + } + + g_return_val_if_fail (id, 0); + return id; +} + +guint +nm_sd_event_attach_default (void) +{ + return event_attach (NULL, NULL); +} + +/*****************************************************************************/ + diff --git a/src/systemd/nm-sd-adapt.h b/src/systemd/nm-sd-adapt.h index 1547f12748..1439aac791 100644 --- a/src/systemd/nm-sd-adapt.h +++ b/src/systemd/nm-sd-adapt.h @@ -26,6 +26,8 @@ #include #include +guint nm_sd_event_attach_default (void); + #define noreturn G_GNUC_NORETURN #ifndef CLOCK_BOOTTIME @@ -115,6 +117,14 @@ G_STMT_START { \ #define ETHERTYPE_LLDP 0x88cc #endif +#ifndef HAVE_SECURE_GETENV +# ifdef HAVE___SECURE_GETENV +# define secure_getenv __secure_getenv +# else +# error neither secure_getenv nor __secure_getenv is available +# endif +#endif + /*****************************************************************************/ /* work around missing uchar.h */ @@ -123,6 +133,14 @@ typedef guint32 char32_t; /*****************************************************************************/ +#define PID_TO_PTR(p) ((void*) ((uintptr_t) p)) + +static inline int +sd_notify (int unset_environment, const char *state) +{ + return 0; +} + /* Can't include both net/if.h and linux/if.h; so have to define this here */ #ifndef IFNAMSIZ #define IFNAMSIZ 16 diff --git a/src/systemd/src/libsystemd/sd-event/sd-event.c b/src/systemd/src/libsystemd/sd-event/sd-event.c index 841358ed03..31e8e7fa66 100644 --- a/src/systemd/src/libsystemd/sd-event/sd-event.c +++ b/src/systemd/src/libsystemd/sd-event/sd-event.c @@ -17,11 +17,15 @@ along with systemd; If not, see . ***/ +#include "nm-sd-adapt.h" + #include #include #include +#if 0 /* NM_IGNORED */ #include "sd-daemon.h" +#endif #include "sd-event.h" #include "sd-id128.h" @@ -30,11 +34,17 @@ #include "hashmap.h" #include "list.h" #include "macro.h" +#if 0 /* NM_IGNORED */ #include "missing.h" +#endif #include "prioq.h" +#if 0 /* NM_IGNORED */ #include "process-util.h" +#endif #include "set.h" +#if 0 /* NM_IGNORED */ #include "signal-util.h" +#endif #include "string-table.h" #include "string-util.h" #include "time-util.h" @@ -1126,6 +1136,7 @@ fail: return r; } +#if 0 /* NM_IGNORED */ static int signal_exit_callback(sd_event_source *s, const struct signalfd_siginfo *si, void *userdata) { assert(s); @@ -1192,6 +1203,7 @@ _public_ int sd_event_add_signal( return 0; } +#endif /* NM_IGNORED */ _public_ int sd_event_add_child( sd_event *e, @@ -2818,6 +2830,7 @@ _public_ int sd_event_default(sd_event **ret) { return 1; } +#if 0 /* NM_IGNORED */ _public_ int sd_event_get_tid(sd_event *e, pid_t *tid) { assert_return(e, -EINVAL); assert_return(tid, -EINVAL); @@ -2889,3 +2902,4 @@ _public_ int sd_event_get_watchdog(sd_event *e) { return e->watchdog; } +#endif /* NM_IGNORED */ diff --git a/src/systemd/src/libsystemd/sd-id128/sd-id128.c b/src/systemd/src/libsystemd/sd-id128/sd-id128.c index ea09d19e4e..01b805a104 100644 --- a/src/systemd/src/libsystemd/sd-id128/sd-id128.c +++ b/src/systemd/src/libsystemd/sd-id128/sd-id128.c @@ -155,7 +155,6 @@ _public_ int sd_id128_get_machine(sd_id128_t *ret) { return 0; } -#if 0 /* NM_IGNORED */ _public_ int sd_id128_get_boot(sd_id128_t *ret) { static thread_local sd_id128_t saved_boot_id; static thread_local bool saved_boot_id_valid = false; @@ -211,6 +210,7 @@ _public_ int sd_id128_get_boot(sd_id128_t *ret) { return 0; } +#if 0 /* NM_IGNORED */ _public_ int sd_id128_randomize(sd_id128_t *ret) { sd_id128_t t; int r; diff --git a/src/tests/Makefile.am b/src/tests/Makefile.am index a3447fbf38..597f477f10 100644 --- a/src/tests/Makefile.am +++ b/src/tests/Makefile.am @@ -117,6 +117,7 @@ test_wired_defname_LDADD = \ test_systemd_CFLAGS = \ "-I$(srcdir)/../" \ "-I$(srcdir)/../platform" \ + "-I$(srcdir)/../systemd" \ "-I$(srcdir)/../systemd/src/systemd" test_systemd_SOURCES = \ diff --git a/src/tests/test-systemd.c b/src/tests/test-systemd.c index 2f6c479aca..ceede91a64 100644 --- a/src/tests/test-systemd.c +++ b/src/tests/test-systemd.c @@ -21,6 +21,8 @@ #include "sd-dhcp-client.h" #include "sd-lldp.h" +#include "sd-event.h" +#include "nm-sd-adapt.h" #include "nm-test-utils.h" @@ -57,6 +59,71 @@ test_lldp_create (void) /*****************************************************************************/ +typedef struct { + GMainLoop *mainloop; + sd_event_source *event_source; +} TestSdEventData; + +static int +_test_sd_event_timeout_cb (sd_event_source *s, uint64_t usec, void *userdata) +{ + TestSdEventData *user_data = userdata; + + g_assert (user_data); + g_assert (user_data->mainloop); + g_assert (user_data->event_source); + + user_data->event_source = sd_event_source_unref (user_data->event_source); + g_main_loop_quit (user_data->mainloop); + return 0; +} + +static void +test_sd_event (void) +{ + int repeat; + + for (repeat = 0; repeat < 2; repeat++) { + guint sd_id = 0; + int r; + int i, n; + sd_event *other_events[3] = { NULL }, *event = NULL; + TestSdEventData user_data = { 0 }; + + g_assert_cmpint (sd_event_default (NULL), ==, 0); + + for (i = 0, n = (nmtst_get_rand_int () % (G_N_ELEMENTS (other_events) + 1)); i < n; i++) { + r = sd_event_default (&other_events[i]); + g_assert (r >= 0 && other_events[i]); + } + + sd_id = nm_sd_event_attach_default (); + + r = sd_event_default (&event); + g_assert (r >= 0 && event); + + r = sd_event_add_time (event, &user_data.event_source, CLOCK_MONOTONIC, 1, 0, _test_sd_event_timeout_cb, &user_data); + g_assert (r >= 0 && user_data.event_source); + + user_data.mainloop = g_main_loop_new (NULL, FALSE); + g_main_loop_run (user_data.mainloop); + g_main_loop_unref (user_data.mainloop); + + g_assert (!user_data.event_source); + + event = sd_event_unref (event); + for (i = 0, n = (nmtst_get_rand_int () % (G_N_ELEMENTS (other_events) + 1)); i < n; i++) + other_events[i] = sd_event_unref (other_events[i]); + nm_clear_g_source (&sd_id); + for (i = 0, n = G_N_ELEMENTS (other_events); i < n; i++) + other_events[i] = sd_event_unref (other_events[i]); + + g_assert_cmpint (sd_event_default (NULL), ==, 0); + } +} + +/*****************************************************************************/ + NMTST_DEFINE (); int @@ -66,6 +133,7 @@ main (int argc, char **argv) g_test_add_func ("/systemd/dhcp/create", test_dhcp_create); g_test_add_func ("/systemd/lldp/create", test_lldp_create); + g_test_add_func ("/systemd/sd-event", test_sd_event); return g_test_run (); }