'\" t .TH "SD_BUS_SET_WATCH_BIND" "3" "" "systemd 256~rc3" "sd_bus_set_watch_bind" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .\" http://bugs.debian.org/507673 .\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" ----------------------------------------------------------------- .\" * set default formatting .\" ----------------------------------------------------------------- .\" disable hyphenation .nh .\" disable justification (adjust text to left margin only) .ad l .\" ----------------------------------------------------------------- .\" * MAIN CONTENT STARTS HERE * .\" ----------------------------------------------------------------- .SH "NAME" sd_bus_set_watch_bind, sd_bus_get_watch_bind \- Control socket binding watching on bus connections .SH "SYNOPSIS" .sp .ft B .nf #include .fi .ft .HP \w'int\ sd_bus_set_watch_bind('u .BI "int sd_bus_set_watch_bind(sd_bus\ *" "bus" ", int\ " "b" ");" .HP \w'int\ sd_bus_get_watch_bind('u .BI "int sd_bus_get_watch_bind(sd_bus\ *" "bus" ");" .SH "DESCRIPTION" .PP \fBsd_bus_set_watch_bind()\fR may be used to enable or disable client\-side watching of server socket binding for a bus connection object\&. If the \fIb\fR is true, the feature is enabled, otherwise disabled (which is the default)\&. When enabled, and the selected bus address refers to an AF_UNIX socket in the file system which does not exist while the connection attempt is made an \fBinotify\fR(7) watch is installed on it, waiting for the socket to appear\&. As soon as the socket appears the connection is made\&. This functionality is useful in particular in early\-boot programs that need to run before the system bus is available, but want to connect to it the instant it may be connected to\&. .PP \fBsd_bus_get_watch_bind()\fR may be used to query the current setting of this feature\&. It returns zero when the feature is disabled, and positive if enabled\&. .PP Note that no timeout is applied while we wait for the socket to appear\&. This means that any synchronous remote operation (such as \fBsd_bus_call\fR(3), \fBsd_bus_add_match\fR(3) or \fBsd_bus_request_name\fR(3)), that is used on a connection with this feature enabled that hasn\*(Aqt been established yet, might block forever if the socket is never created\&. However, asynchronous remote operations (such as \fBsd_bus_send\fR(3), \fBsd_bus_call_async\fR(3), \fBsd_bus_add_match_async\fR(3)) do not block in this case, and safely enqueue the requested operations to be dispatched the instant the connection is set up\&. .PP Use \fBsd_bus_is_ready\fR(3) to determine whether the connection is fully established, i\&.e\&. whether the peer socket has been bound, connected to and authenticated\&. Use \fBsd_bus_set_connected_signal\fR(3) to be notified when the connection is fully established\&. .SH "RETURN VALUE" .PP On success, these functions return 0 or a positive integer\&. On failure, they return a negative errno\-style error code\&. .SS "Errors" .PP Returned errors may indicate the following problems: .PP \fB\-ECHILD\fR .RS 4 The bus connection has been created in a different process, library or module instance\&. .RE .SH "NOTES" .PP Functions described here are available as a shared library, which can be compiled against and linked to with the \fBlibsystemd\fR\ \&\fBpkg-config\fR(1) file\&. .PP The code described here uses \fBgetenv\fR(3), which is declared to be not multi\-thread\-safe\&. This means that the code calling the functions described here must not call \fBsetenv\fR(3) from a parallel thread\&. It is recommended to only do calls to \fBsetenv()\fR from an early phase of the program when no other threads have been started\&. .SH "EXAMPLE" .PP \fBExample\ \&1.\ \&Create a simple system service that publishes a property on the system bus and can reconnect when D\-Bus disconnects and reconnects\fR .sp .if n \{\ .RS 4 .\} .nf /* SPDX\-License\-Identifier: MIT\-0 */ /* A D\-Bus service that automatically reconnects when the system bus is * restarted\&. * * Compile with \*(Aqcc sd_bus_service_reconnect\&.c $(pkg\-config \-\-libs \-\-cflags libsystemd)\*(Aq * * To allow the program to take ownership of the name \*(Aqorg\&.freedesktop\&.ReconnectExample\*(Aq, * add the following as /etc/dbus\-1/system\&.d/org\&.freedesktop\&.ReconnectExample\&.conf * and then reload the broker with \*(Aqsystemctl reload dbus\*(Aq: * * To get the property via busctl: * * $ busctl \-\-user get\-property org\&.freedesktop\&.ReconnectExample \e * /org/freedesktop/ReconnectExample \e * org\&.freedesktop\&.ReconnectExample \e * Example * s "example" */ #include #include #include #include #define _cleanup_(f) __attribute__((cleanup(f))) static int log_error(int r, const char *str) { fprintf(stderr, "%s failed: %s\en", str, strerror(\-r)); return r; } typedef struct object { const char *example; sd_bus **bus; sd_event **event; } object; static int property_get( sd_bus *bus, const char *path, const char *interface, const char *property, sd_bus_message *reply, void *userdata, sd_bus_error *error) { object *o = userdata; if (strcmp(property, "Example") == 0) return sd_bus_message_append(reply, "s", o\->example); return sd_bus_error_setf(error, SD_BUS_ERROR_UNKNOWN_PROPERTY, "Unknown property \*(Aq%s\*(Aq", property); } /* https://www\&.freedesktop\&.org/software/systemd/man/sd_bus_add_object\&.html */ static const sd_bus_vtable vtable[] = { SD_BUS_VTABLE_START(0), SD_BUS_PROPERTY( "Example", "s", property_get, 0, SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_VTABLE_END }; static int setup(object *o); static int on_disconnect(sd_bus_message *message, void *userdata, sd_bus_error *ret_error) { int r; r = setup((object *)userdata); if (r < 0) { object *o = userdata; r = sd_event_exit(*o\->event, r); if (r < 0) return log_error(r, "sd_event_exit()"); } return 1; } /* Ensure the event loop exits with a clear error if acquiring the well\-known * service name fails */ static int request_name_callback(sd_bus_message *m, void *userdata, sd_bus_error *ret_error) { int r; if (!sd_bus_message_is_method_error(m, NULL)) return 1; const sd_bus_error *error = sd_bus_message_get_error(m); if (sd_bus_error_has_names(error, SD_BUS_ERROR_TIMEOUT, SD_BUS_ERROR_NO_REPLY)) return 1; /* The bus is not available, try again later */ fprintf(stderr, "Failed to request name: %s\en", error\->message); object *o = userdata; r = sd_event_exit(*o\->event, \-sd_bus_error_get_errno(error)); if (r < 0) return log_error(r, "sd_event_exit()"); return 1; } static int setup(object *o) { int r; /* If we are reconnecting, then the bus object needs to be closed, detached * from the event loop and recreated\&. * https://www\&.freedesktop\&.org/software/systemd/man/sd_bus_detach_event\&.html * https://www\&.freedesktop\&.org/software/systemd/man/sd_bus_close_unref\&.html */ if (*o\->bus) { r = sd_bus_detach_event(*o\->bus); if (r < 0) return log_error(r, "sd_bus_detach_event()"); *o\->bus = sd_bus_close_unref(*o\->bus); } /* Set up a new bus object for the system bus, configure it to wait for D\-Bus * to be available instead of failing if it is not, and start it\&. All the * following operations are asynchronous and will not block waiting for D\-Bus * to be available\&. * https://www\&.freedesktop\&.org/software/systemd/man/sd_bus_new\&.html * https://www\&.freedesktop\&.org/software/systemd/man/sd_bus_set_address\&.html * https://www\&.freedesktop\&.org/software/systemd/man/sd_bus_set_bus_client\&.html * https://www\&.freedesktop\&.org/software/systemd/man/sd_bus_negotiate_creds\&.html * https://www\&.freedesktop\&.org/software/systemd/man/sd_bus_set_watch_bind\&.html * https://www\&.freedesktop\&.org/software/systemd/man/sd_bus_set_connected_signal\&.html * https://www\&.freedesktop\&.org/software/systemd/man/sd_bus_start\&.html */ r = sd_bus_new(o\->bus); if (r < 0) return log_error(r, "sd_bus_new()"); r = sd_bus_set_address(*o\->bus, "unix:path=/run/dbus/system_bus_socket"); if (r < 0) return log_error(r, "sd_bus_set_address()"); r = sd_bus_set_bus_client(*o\->bus, 1); if (r < 0) return log_error(r, "sd_bus_set_bus_client()"); r = sd_bus_negotiate_creds(*o\->bus, 1, SD_BUS_CREDS_UID|SD_BUS_CREDS_EUID|SD_BUS_CREDS_EFFECTIVE_CAPS); if (r < 0) return log_error(r, "sd_bus_negotiate_creds()"); r = sd_bus_set_watch_bind(*o\->bus, 1); if (r < 0) return log_error(r, "sd_bus_set_watch_bind()"); r = sd_bus_start(*o\->bus); if (r < 0) return log_error(r, "sd_bus_start()"); /* Publish an interface on the bus, specifying our well\-known object access * path and public interface name\&. * https://www\&.freedesktop\&.org/software/systemd/man/sd_bus_add_object\&.html * https://dbus\&.freedesktop\&.org/doc/dbus\-tutorial\&.html */ r = sd_bus_add_object_vtable(*o\->bus, NULL, "/org/freedesktop/ReconnectExample", "org\&.freedesktop\&.ReconnectExample", vtable, o); if (r < 0) return log_error(r, "sd_bus_add_object_vtable()"); /* By default the service is only assigned an ephemeral name\&. Also add a * well\-known one, so that clients know whom to call\&. This needs to be * asynchronous, as D\-Bus might not be yet available\&. The callback will check * whether the error is expected or not, in case it fails\&. * https://www\&.freedesktop\&.org/software/systemd/man/sd_bus_request_name\&.html */ r = sd_bus_request_name_async(*o\->bus, NULL, "org\&.freedesktop\&.ReconnectExample", 0, request_name_callback, o); if (r < 0) return log_error(r, "sd_bus_request_name_async()"); /* When D\-Bus is disconnected this callback will be invoked, which will set up * the connection again\&. This needs to be asynchronous, as D\-Bus might not yet * be available\&. * https://www\&.freedesktop\&.org/software/systemd/man/sd_bus_match_signal_async\&.html */ r = sd_bus_match_signal_async(*o\->bus, NULL, "org\&.freedesktop\&.DBus\&.Local", NULL, "org\&.freedesktop\&.DBus\&.Local", "Disconnected", on_disconnect, NULL, o); if (r < 0) return log_error(r, "sd_bus_match_signal_async()"); /* Attach the bus object to the event loop so that calls and signals are * processed\&. * https://www\&.freedesktop\&.org/software/systemd/man/sd_bus_attach_event\&.html */ r = sd_bus_attach_event(*o\->bus, *o\->event, 0); if (r < 0) return log_error(r, "sd_bus_attach_event()"); return 0; } int main(int argc, char **argv) { /* The bus should be relinquished before the program terminates\&. The cleanup * attribute allows us to do it nicely and cleanly whenever we exit the block\&. */ _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL; _cleanup_(sd_event_unrefp) sd_event *event = NULL; object o = { \&.example = "example", \&.bus = &bus, \&.event = &event, }; int r; /* Create an event loop data structure, with default parameters\&. * https://www\&.freedesktop\&.org/software/systemd/man/sd_event_default\&.html */ r = sd_event_default(&event); if (r < 0) return log_error(r, "sd_event_default()"); /* By default the event loop will terminate when all sources have disappeared, * so we have to keep it \*(Aqoccupied\*(Aq\&. Register signal handling to do so\&. * https://www\&.freedesktop\&.org/software/systemd/man/sd_event_add_signal\&.html */ r = sd_event_add_signal(event, NULL, SIGINT|SD_EVENT_SIGNAL_PROCMASK, NULL, NULL); if (r < 0) return log_error(r, "sd_event_add_signal(SIGINT)"); r = sd_event_add_signal(event, NULL, SIGTERM|SD_EVENT_SIGNAL_PROCMASK, NULL, NULL); if (r < 0) return log_error(r, "sd_event_add_signal(SIGTERM)"); r = setup(&o); if (r < 0) return EXIT_FAILURE; /* Enter the main loop, it will exit only on sigint/sigterm\&. * https://www\&.freedesktop\&.org/software/systemd/man/sd_event_loop\&.html */ r = sd_event_loop(event); if (r < 0) return log_error(r, "sd_event_loop()"); /* https://www\&.freedesktop\&.org/software/systemd/man/sd_bus_release_name\&.html */ r = sd_bus_release_name(bus, "org\&.freedesktop\&.ReconnectExample"); if (r < 0) return log_error(r, "sd_bus_release_name()"); return 0; } .fi .if n \{\ .RE .\} .PP This is particularly useful for services that are configured to survive a soft\-reboot, see \fBsystemd-soft-reboot.service\fR(8) for more details\&. .SH "HISTORY" .PP \fBsd_bus_set_watch_bind()\fR and \fBsd_bus_get_watch_bind()\fR were added in version 237\&. .SH "SEE ALSO" .PP \fBsystemd\fR(1), \fBsd-bus\fR(3), \fBinotify\fR(7), \fBsd_bus_call\fR(3), \fBsd_bus_add_match\fR(3), \fBsd_bus_request_name\fR(3), \fBsd_bus_is_ready\fR(3), \fBsd_bus_set_connected_signal\fR(3)