Merge authors: James Hunt (jamesodhunt) Related merge proposals: https://code.launchpad.net/~jamesodhunt/upstart/upstart-local-bridge/+merge/177027 proposed by: James Hunt (jamesodhunt) review: Approve - Dmitrijs Ledkovs (xnox) ------------------------------------------------------------ revno: 1515 [merge] committer: Dmitrijs Ledkovs <[email protected]> branch nick: upstart timestamp: Mon 2013-07-29 13:30:52 +0100 message: Merge lp:~jamesodhunt/upstart/upstart-local-bridge added: extra/man/upstart-local-bridge.8 extra/upstart-local-bridge.c modified: ChangeLog extra/Makefile.am
-- lp:upstart https://code.launchpad.net/~upstart-devel/upstart/trunk Your team Upstart Reviewers is subscribed to branch lp:upstart. To unsubscribe from this branch go to https://code.launchpad.net/~upstart-devel/upstart/trunk/+edit-subscription
=== modified file 'ChangeLog' --- ChangeLog 2013-07-24 09:40:15 +0000 +++ ChangeLog 2013-07-25 19:44:38 +0000 @@ -1,8 +1,30 @@ +2013-07-25 James Hunt <[email protected]> + + * extra/Makefile.am: Renamed to upstart-local-bridge. + * extra/man/upstart-local-bridge.8: Removed inet type details. + * extra/upstart-local-bridge.c: + - Removed inet socket handling. + - General clean-up. + +2013-07-24 James Hunt <[email protected]> + + * extra/man/upstart-text-bridge.8: Added extra variables. + * extra/upstart-text-bridge.c: socket_reader(): + - Fixed assertion failure caused by passing invalid address of fd. + - Added new standard environment variables to event. + 2013-07-24 James Hunt <[email protected]> * extra/upstart-dbus-bridge.c: signal_filter(): Use inttype macros to ensure portability. +2013-07-23 James Hunt <[email protected]> + + * extra/upstart-text-bridge.c: New bridge. + * extra/Makefile.am: Updated for new bridge. + * extra/man/upstart-text-bridge.8: New man page. + * extra/Makefile.am: Added man page for text-bridge. + 2013-07-19 Dmitrijs Ledkovs <[email protected]> * init/session.c: fix a bug in session_from_index to handle more === modified file 'extra/Makefile.am' --- extra/Makefile.am 2013-07-24 04:41:18 +0000 +++ extra/Makefile.am 2013-07-25 19:44:38 +0000 @@ -28,7 +28,8 @@ upstart-socket-bridge \ upstart-event-bridge \ upstart-file-bridge \ - upstart-dbus-bridge + upstart-dbus-bridge \ + upstart-local-bridge dist_init_DATA = \ conf/upstart-socket-bridge.conf \ @@ -41,6 +42,7 @@ man/upstart-event-bridge.8 \ man/upstart-file-bridge.8 \ man/upstart-dbus-bridge.8 \ + man/upstart-local-bridge.8 \ man/socket-event.7 \ man/file-event.7 \ man/dbus-event.7 @@ -89,6 +91,17 @@ $(NIH_DBUS_LIBS) \ $(DBUS_LIBS) +upstart_local_bridge_SOURCES = \ + upstart-local-bridge.c +nodist_upstart_local_bridge_SOURCES = \ + $(com_ubuntu_Upstart_OUTPUTS) \ + $(com_ubuntu_Upstart_Job_OUTPUTS) +upstart_local_bridge_LDADD = \ + $(LTLIBINTL) \ + $(NIH_LIBS) \ + $(NIH_DBUS_LIBS) \ + $(DBUS_LIBS) + if HAVE_UDEV dist_init_DATA += \ conf/upstart-udev-bridge.conf === added file 'extra/man/upstart-local-bridge.8' --- extra/man/upstart-local-bridge.8 1970-01-01 00:00:00 +0000 +++ extra/man/upstart-local-bridge.8 2013-07-25 19:46:56 +0000 @@ -0,0 +1,123 @@ +.TH upstart\-local\-bridge 8 2013-07-23 upstart +.\" +.SH NAME +upstart\-local\-bridge \- Bridge between Upstart and a local client socket +connection. +.\" +.SH SYNOPSIS +.B upstart\-local\-bridge +.RI [ OPTIONS ]... +.\" +.SH DESCRIPTION +.B upstart\-local\-bridge +listens on a local domain socket for name=value pairs and creates +.BR init (8) +events for them. + +The local unix domain socket can be either named or abstract. +.\" +.SH OPTIONS +.\" +.TP +.B \-\-any\-user +By default the bridge will only accept connections from clients running +under the same user ID as the bridge itself. This option allows +connections from any user. +.\" +.TP +.B \-\-daemon +Detach and run in the background. +.\" +.TP +.B \-\-debug +Enable debugging output. +.\" +.TP +.B \-\-event \fIevent\fP +Specify name of event to emit on receipt of a name=value pair. +.\" +.TP +.B \-\-help +Show brief usage summary. +.\" +.TP +.B \-\-path \fIpath\fP +Specify path for local/abstract socket to listen on. If the first byte of +.I path +is an \(aq\fI@\fP\(aq, the socket will be created as an abstract socket. +.\" +.TP +.B \-\-verbose +Enable verbose output. +.\" +.SH EVENT DETAILS + +The following environment variables are added automatically to the event +to be emitted, with the name=value pair being added as the last variable. +.P +.IP \(bu 4 +SOCKET_TYPE=unix +.IP \(bu 4 +SOCKET_VARIANT=[\fInamed\fP|\fIabstract\fP] +Sub-type of socket. +.IP \(bu 4 +CLIENT_UID=\fIUID\fP +User ID of connected client. +.IP \(bu 4 +CLIENT_GID=\fIGID\fP +Group ID of connected client. +.IP \(bu 4 +CLIENT_PID=\fIPID\fP +Process ID of connected client. +.IP \(bu 4 +PATH=\fIPATH\fP +.P +.\" +.SH EXAMPLES +.IP "upstart\-local\-bridge \-\-event=foo \-\-path=/var/foo/bar" 0.4i +Listen on local socket +.I /var/foo/bar +and when a name=value pair is read, emit an event of the form: + +.RS +.nf +foo SOCKET_TYPE=unix SOCKET_VARIANT=named PATH=/var/foo/bar name=value +.fi +.RE +.IP "upstart\-local\-bridge \-\-event=bar \-\-path=@/var/foo/bar" 0.4i +Listen on abstract socket +.I @/var/foo/bar +and when a name=value pair is read, emit an event of the form: + +.RS +.nf +bar SOCKET_TYPE=unix SOCKET_VARIANT=abstract PATH=@/var/foo/bar name=value +.fi +.RE +.\" +.SH NOTES +.IP \(bu 4 +If a named local socket is specified, all path elements except +for the last must already exist before the bridge starts. +.\" +.SH LIMITATIONS + +.IP \(bu 4 +Only a single client connection is serviced at any one time. +.\" +.SH AUTHOR +Written by James Hunt +.RB < [email protected] > +.\" +.SH BUGS +Report bugs at +.RB < https://launchpad.net/ubuntu/+source/upstart/+bugs > +.\" +.SH COPYRIGHT +Copyright \(co 2013 Canonical Ltd. +.PP +This is free software; see the source for copying conditions. There is NO +warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +.SH SEE ALSO +.BR init (5) +.BR init (8) === added file 'extra/upstart-local-bridge.c' --- extra/upstart-local-bridge.c 1970-01-01 00:00:00 +0000 +++ extra/upstart-local-bridge.c 2013-07-25 19:55:45 +0000 @@ -0,0 +1,805 @@ +/* upstart + * + * Copyright © 2013 Canonical Ltd. + * Author: James Hunt <[email protected]> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif /* HAVE_CONFIG_H */ + +#include <sys/types.h> +#include <sys/socket.h> +#include <sys/un.h> + +#include <errno.h> +#include <stdlib.h> +#include <string.h> +#include <syslog.h> +#include <unistd.h> + +#include <nih/macros.h> +#include <nih/alloc.h> +#include <nih/list.h> +#include <nih/hash.h> +#include <nih/string.h> +#include <nih/io.h> +#include <nih/option.h> +#include <nih/main.h> +#include <nih/logging.h> +#include <nih/error.h> + +#include <nih-dbus/dbus_connection.h> +#include <nih-dbus/dbus_proxy.h> + +#include "dbus/upstart.h" +#include "com.ubuntu.Upstart.h" +#include "com.ubuntu.Upstart.Job.h" + +/** + * Job: + * + * @entry: list header, + * @path: D-Bus path for a job. + * + * Representation of an Upstart Job. + * + **/ +typedef struct job { + NihList entry; + char *path; +} Job; + +/** + * Socket: + * + * @addr/sun_addr: socket address, + * @addrlen: length of sun_addr, + * @sock: file descriptor of socket, + * @watch: IO Watch used to detect client activity. + * + * Representation of a socket(2). + **/ +typedef struct socket { + union { + struct sockaddr addr; /* Generic type */ + struct sockaddr_un sun_addr; /* local/domain/unix/abstract socket */ + }; + socklen_t addrlen; + + int sock; + NihIoWatch *watch; +} Socket; + +/** + * ClientConnection: + * + * @sock: socket client connected via, + * @fd: file descriptor client connected on, + * @ucred: client credentials. + * + * Representation of a connected client. + **/ +typedef struct client_connection { + Socket *sock; + int fd; + struct ucred ucred; +} ClientConnection; + +static void upstart_job_added (void *data, NihDBusMessage *message, + const char *job); +static void upstart_job_removed (void *data, NihDBusMessage *message, + const char *job); +static void upstart_connect (void); +static void upstart_disconnected (DBusConnection *connection); + +static Socket *create_socket (void *parent); + +static void socket_watcher (Socket *sock, NihIoWatch *watch, + NihIoEvents events); + +static void socket_reader (ClientConnection *client, NihIo *io, + const char *buf, size_t len); + +static void close_handler (ClientConnection *client, NihIo *io); + +static void emit_event_error (void *data, NihDBusMessage *message); + +static void signal_handler (void *data, NihSignal *signal); + +static void cleanup (void); + +/** + * daemonise: + * + * Set to TRUE if we should become a daemon, rather than just running + * in the foreground. + **/ +static int daemonise = FALSE; + +/** + * jobs: + * + * Jobs that we're monitoring. + **/ +static NihHash *jobs = NULL; + +/** + * upstart: + * + * Proxy to Upstart daemon. + **/ +static NihDBusProxy *upstart = NULL; + +/** + * event_name: + * + * Name of event this bridge emits. + **/ +static char *event_name = NULL; + +/** + * Unix (local) domain socket path. + * + * Abstract sockets will have '@' as first character. + **/ +static char *socket_path = NULL; + +/** + * socket_type: + * + * Type of socket supported by this bridge. + **/ +static char *socket_type = "unix"; + +/** + * socket_name: + * + * Human-readable socket name in form: + * + * unix:[@]/some/path + **/ +static char *socket_name = NULL; + +/** + * sock: + * + * Socket this bridge listens on. + **/ +static Socket *sock = NULL; + +/** + * any_user: + * + * If FALSE, only accept connections from the same uid as + * user the bridge runs as. + * If TRUE, accept connections from any user. + **/ +static int any_user = FALSE; + +/** + * options: + * + * Command-line options accepted by this program. + **/ +static NihOption options[] = { + { 0, "daemon", N_("Detach and run in the background"), + NULL, NULL, &daemonise, NULL }, + + { 0, "event", N_("specify name of event to emit on receipt of name=value pair"), + NULL, "EVENT", &event_name, NULL }, + + { 0, "any-user", N_("allow any user to connect"), + NULL, NULL, &any_user, NULL }, + + { 0, "path", N_("specify path for local/abstract socket to use"), + NULL, "PATH", &socket_path, NULL }, + + NIH_OPTION_LAST +}; + + +/** + * signal_handler: + * @data: unused, + * @signal: signal caught. + * + * Called when we receive the TERM/INT signal. + **/ +static void +signal_handler (void *data, + NihSignal *signal) +{ + nih_assert (signal != NULL); + + cleanup (); + + nih_main_loop_exit (0); +} + +/** + * cleanup: + * + * Perform final operations before exit. + **/ +static void +cleanup (void) +{ + nih_assert (sock); + + close (sock->sock); + + if (sock->sun_addr.sun_path[0] != '@') + unlink (sock->sun_addr.sun_path); +} + +int +main (int argc, + char *argv[]) +{ + char **args; + int ret; + + nih_main_init (argv[0]); + + nih_option_set_synopsis (_("Local socket Upstart Bridge")); + nih_option_set_help ( + _("By default, this bridge does not detach from the " + "console and remains in the foreground. Use the --daemon " + "option to have it detach.")); + + args = nih_option_parser (NULL, argc, argv, options, FALSE); + if (! args) + exit (1); + + if (! event_name) { + nih_fatal ("%s", _("Must specify event name")); + exit (1); + } + + /* Allocate jobs hash table */ + jobs = NIH_MUST (nih_hash_string_new (NULL, 0)); + + sock = create_socket (NULL); + if (! sock) { + nih_fatal ("%s %s", + _("Failed to create socket"), + socket_name); + exit (1); + } + + nih_debug ("Connected to socket '%s' on fd %d", socket_name, sock->sock); + + upstart_connect (); + + /* Become daemon */ + if (daemonise) { + if (nih_main_daemonise () < 0) { + NihError *err; + + err = nih_error_get (); + nih_fatal ("%s: %s", _("Unable to become daemon"), + err->message); + nih_free (err); + + exit (1); + } + + /* Send all logging output to syslog */ + openlog (program_name, LOG_PID, LOG_DAEMON); + nih_log_set_logger (nih_logger_syslog); + } + + nih_signal_set_handler (SIGTERM, nih_signal_handler); + NIH_MUST (nih_signal_add_handler (NULL, SIGTERM, signal_handler, NULL)); + + nih_signal_set_handler (SIGINT, nih_signal_handler); + NIH_MUST (nih_signal_add_handler (NULL, SIGINT, signal_handler, NULL)); + + /* Handle TERM and INT signals gracefully */ + nih_signal_set_handler (SIGTERM, nih_signal_handler); + NIH_MUST (nih_signal_add_handler (NULL, SIGTERM, nih_main_term_signal, NULL)); + + if (! daemonise) { + nih_signal_set_handler (SIGINT, nih_signal_handler); + NIH_MUST (nih_signal_add_handler (NULL, SIGINT, nih_main_term_signal, NULL)); + } + + ret = nih_main_loop (); + + return ret; +} + +static void +upstart_job_added (void *data, + NihDBusMessage *message, + const char *job_class_path) +{ + nih_local NihDBusProxy *job_class = NULL; + nih_local char ***start_on = NULL; + nih_local char ***stop_on = NULL; + Job *job; + + nih_assert (job_class_path != NULL); + + /* Obtain a proxy to the job */ + job_class = nih_dbus_proxy_new (NULL, upstart->connection, + upstart->name, job_class_path, + NULL, NULL); + if (! job_class) { + NihError *err; + + err = nih_error_get (); + nih_error ("Could not create proxy for job %s: %s", + job_class_path, err->message); + nih_free (err); + + return; + } + + job_class->auto_start = FALSE; + + /* Obtain the start_on and stop_on properties of the job */ + if (job_class_get_start_on_sync (NULL, job_class, &start_on) < 0) { + NihError *err; + + err = nih_error_get (); + nih_error ("Could not obtain job start condition %s: %s", + job_class_path, err->message); + nih_free (err); + + return; + } + + if (job_class_get_stop_on_sync (NULL, job_class, &stop_on) < 0) { + NihError *err; + + err = nih_error_get (); + nih_error ("Could not obtain job stop condition %s: %s", + job_class_path, err->message); + nih_free (err); + + return; + } + + /* Free any existing record for the job (should never happen, + * but worth being safe). + */ + job = (Job *)nih_hash_lookup (jobs, job_class_path); + if (job) + nih_free (job); + + /* Create new record for the job */ + job = NIH_MUST (nih_new (NULL, Job)); + job->path = NIH_MUST (nih_strdup (job, job_class_path)); + + nih_list_init (&job->entry); + + nih_debug ("Job got added %s", job_class_path); + + nih_alloc_set_destructor (job, nih_list_destroy); + + /* Add all jobs */ + nih_hash_add (jobs, &job->entry); +} + +static void +upstart_job_removed (void *data, + NihDBusMessage *message, + const char *job_path) +{ + Job *job; + + nih_assert (job_path != NULL); + + job = (Job *)nih_hash_lookup (jobs, job_path); + if (job) { + nih_debug ("Job went away %s", job_path); + nih_free (job); + } +} + +static void +upstart_connect (void) +{ + DBusConnection *connection; + char **job_class_paths; + + /* Initialise the connection to Upstart */ + connection = NIH_SHOULD (nih_dbus_connect (DBUS_ADDRESS_UPSTART, upstart_disconnected)); + if (! connection) { + NihError *err; + + err = nih_error_get (); + nih_fatal ("%s: %s", _("Could not connect to Upstart"), + err->message); + nih_free (err); + + exit (1); + } + + upstart = NIH_SHOULD (nih_dbus_proxy_new (NULL, connection, + NULL, DBUS_PATH_UPSTART, + NULL, NULL)); + if (! upstart) { + NihError *err; + + err = nih_error_get (); + nih_fatal ("%s: %s", _("Could not create Upstart proxy"), + err->message); + nih_free (err); + + exit (1); + } + + nih_debug ("Connected to Upstart"); + + /* Connect signals to be notified when jobs come and go */ + if (! nih_dbus_proxy_connect (upstart, &upstart_com_ubuntu_Upstart0_6, "JobAdded", + (NihDBusSignalHandler)upstart_job_added, NULL)) { + NihError *err; + + err = nih_error_get (); + nih_fatal ("%s: %s", _("Could not create JobAdded signal connection"), + err->message); + nih_free (err); + + exit (1); + } + + if (! nih_dbus_proxy_connect (upstart, &upstart_com_ubuntu_Upstart0_6, "JobRemoved", + (NihDBusSignalHandler)upstart_job_removed, NULL)) { + NihError *err; + + err = nih_error_get (); + nih_fatal ("%s: %s", _("Could not create JobRemoved signal connection"), + err->message); + nih_free (err); + + exit (1); + } + + /* Request a list of all current jobs */ + if (upstart_get_all_jobs_sync (NULL, upstart, &job_class_paths) < 0) { + NihError *err; + + err = nih_error_get (); + nih_fatal ("%s: %s", _("Could not obtain job list"), + err->message); + nih_free (err); + + exit (1); + } + + for (char **job_class_path = job_class_paths; + job_class_path && *job_class_path; job_class_path++) + upstart_job_added (NULL, NULL, *job_class_path); + + nih_free (job_class_paths); +} + +static void +upstart_disconnected (DBusConnection *connection) +{ + nih_fatal (_("Disconnected from Upstart")); + nih_main_loop_exit (1); +} + +/** + * socket_watcher: + * + * @sock: Socket, + * @watch: IO watch, + * @event: events that occurred. + * + * Called when activity is received for socket fd. + **/ +static void +socket_watcher (Socket *sock, + NihIoWatch *watch, + NihIoEvents events) +{ + struct sockaddr client_addr; + socklen_t client_len; + nih_local char *buffer = NULL; + ClientConnection *client; + size_t len; + + nih_assert (sock); + nih_assert (watch); + + client = NIH_MUST (nih_new (NULL, ClientConnection)); + memset (client, 0, sizeof (ClientConnection)); + client->sock = sock; + + client_len = sizeof (struct sockaddr); + + client->fd = accept (sock->sock, (struct sockaddr *)&client_addr, &client_len); + + if (client->fd < 0) { + nih_fatal ("%s %s %s", _("Failed to accept socket"), + socket_name, strerror (errno)); + return; + } + + len = sizeof (client->ucred); + + /* Establish who is connected to the other end */ + if (getsockopt (client->fd, SOL_SOCKET, SO_PEERCRED, &client->ucred, &len) < 0) + goto error; + + if (! any_user && client->ucred.uid != geteuid ()) { + nih_warn ("Ignoring request from uid %u (gid %u, pid %u)", + (unsigned int)client->ucred.uid, + (unsigned int)client->ucred.gid, + (unsigned int)client->ucred.pid); + close (client->fd); + return; + } + + nih_debug ("Client connected via local socket to %s: " + "pid %d (uid %d, gid %d)", + socket_name, + client->ucred.pid, + client->ucred.uid, + client->ucred.gid); + + /* Wait for remote end to send data */ + NIH_MUST (nih_io_reopen (sock, client->fd, + NIH_IO_STREAM, + (NihIoReader)socket_reader, + (NihIoCloseHandler)close_handler, + NULL, + client)); + return; + +error: + nih_warn ("%s %s: %s", + _("Cannot establish peer credentials for socket"), + socket_name, strerror (errno)); +} + +/** + * socket_reader: + * + * @client: client connection, + * @io: NihIo, + * @buf: data read from client, + * @len: length of @buf. + * + * NihIoReader function called when data has been read from the + * connected client. + **/ +static void +socket_reader (ClientConnection *client, + NihIo *io, + const char *buf, + size_t len) +{ + DBusPendingCall *pending_call; + nih_local char **env = NULL; + nih_local char *var = NULL; + size_t used_len = 0; + int i; + + nih_assert (sock); + nih_assert (client); + nih_assert (io); + nih_assert (buf); + + /* Ignore messages that are too short */ + if (len < 2) + goto error; + + /* Ensure the data is a name=value pair */ + if (! strchr (buf, '=') || buf[0] == '=') + goto error; + + /* Remove line endings */ + for (i = 0, used_len = len; i < 2; i++) { + if (buf[used_len-1] == '\n' || buf[used_len-1] == '\r') + used_len--; + else + break; + } + + /* Second check to ensure overly short messages are ignored */ + if (used_len < 2) + goto error; + + /* Construct the event environment. + * + * Note that although the client could conceivably specify one + * of the variables below _itself_, if the intent is malicious + * it will be thwarted since although the following example + * event is valid... + * + * foo BAR=BAZ BAR=MALICIOUS + * + * ... environment variable matching only happens for the first + * occurence of a variable. In summary, a malicious client + * cannot spoof the standard variables we set. + */ + env = NIH_MUST (nih_str_array_new (NULL)); + + /* Specify type to allow for other types to be added in the future */ + var = NIH_MUST (nih_sprintf (NULL, "SOCKET_TYPE=%s", socket_type)); + NIH_MUST (nih_str_array_addp (&env, NULL, NULL, var)); + + var = NIH_MUST (nih_sprintf (NULL, "SOCKET_VARIANT=%s", + sock->sun_addr.sun_path[0] ? "named" : "abstract")); + NIH_MUST (nih_str_array_addp (&env, NULL, NULL, var)); + + var = NIH_MUST (nih_sprintf (NULL, "CLIENT_UID=%u", (unsigned int)client->ucred.uid)); + NIH_MUST (nih_str_array_addp (&env, NULL, NULL, var)); + + var = NIH_MUST (nih_sprintf (NULL, "CLIENT_GID=%u", (unsigned int)client->ucred.gid)); + NIH_MUST (nih_str_array_addp (&env, NULL, NULL, var)); + + var = NIH_MUST (nih_sprintf (NULL, "CLIENT_PID=%u", (unsigned int)client->ucred.pid)); + NIH_MUST (nih_str_array_addp (&env, NULL, NULL, var)); + + var = NIH_MUST (nih_sprintf (NULL, "PATH=%s", socket_path)); + NIH_MUST (nih_str_array_addp (&env, NULL, NULL, var)); + + /* Add the name=value pair */ + NIH_MUST (nih_str_array_addn (&env, NULL, NULL, buf, used_len)); + + pending_call = upstart_emit_event (upstart, + event_name, env, FALSE, + NULL, emit_event_error, NULL, + NIH_DBUS_TIMEOUT_NEVER); + + if (! pending_call) { + NihError *err; + err = nih_error_get (); + nih_warn ("%s", err->message); + nih_free (err); + } + + /* Consume the entire length */ + nih_io_buffer_shrink (io->recv_buf, len); + + dbus_pending_call_unref (pending_call); + + return; + +error: + nih_debug ("ignoring invalid input of length %lu", + (unsigned long int)len); + + /* Consume the entire length */ + nih_io_buffer_shrink (io->recv_buf, len); +} + +static void +close_handler (ClientConnection *client, NihIo *io) +{ + nih_assert (client); + nih_assert (io); + + nih_debug ("Remote end closed connection"); + + close (client->fd); + nih_free (client); + nih_free (io); +} + +/** + * create_socket: + * @parent: Parent pointer. + * + * Create a Socket object, listen on it and arrange for NIH to monitor + * it. + * + * Returns: Newly-allocated Socket on success, or NULL on error. + **/ +static Socket * +create_socket (void *parent) +{ + Socket *sock = NULL; + int opt = 1; + size_t len; + + if (! socket_path) { + nih_fatal ("%s", _("Must specify socket path")); + exit (1); + } + + NIH_MUST (nih_strcat_sprintf (&socket_name, NULL, "%s:%s", + socket_type, socket_path)); + + sock = NIH_MUST (nih_new (NULL, Socket)); + memset (sock, 0, sizeof (Socket)); + sock->sock = -1; + + sock->sun_addr.sun_family = AF_UNIX; + + if (! *socket_path || (socket_path[0] != '/' && socket_path[0] != '@')) { + nih_fatal ("%s %s", _("Invalid path"), socket_path); + goto error; + } + + len = strlen (socket_path); + + if (len > sizeof (sock->sun_addr.sun_path)) { + nih_fatal ("%s %s", _("Path too long"), socket_path); + goto error; + } + + strncpy (sock->sun_addr.sun_path, socket_path, + sizeof (sock->sun_addr.sun_path)); + + sock->addrlen = sizeof (sock->sun_addr.sun_family) + len; + + /* Handle abstract names */ + if (sock->sun_addr.sun_path[0] == '@') + sock->sun_addr.sun_path[0] = '\0'; + + sock->sock = socket (sock->addr.sa_family, SOCK_STREAM, 0); + if (sock->sock < 0) { + nih_fatal ("%s %s %s", _("Failed to create socket"), + socket_name, strerror (errno)); + goto error; + } + + if (setsockopt (sock->sock, SOL_SOCKET, SO_REUSEADDR, + &opt, sizeof (opt)) < 0) { + nih_fatal ("%s %s %s", _("Failed to set socket reuse"), + socket_name, strerror (errno)); + goto error; + } + + if (setsockopt (sock->sock, SOL_SOCKET, SO_PASSCRED, + &opt, sizeof (opt)) < 0) { + nih_fatal ("%s %s %s", _("Failed to set socket credential-passing"), + socket_name, strerror (errno)); + goto error; + } + + if (bind (sock->sock, &sock->addr, sock->addrlen) < 0) { + nih_fatal ("%s %s %s", _("Failed to bind socket"), + socket_name, strerror (errno)); + goto error; + } + + if (listen (sock->sock, SOMAXCONN) < 0) { + nih_fatal ("%s %s %s", _("Failed to listen on socket"), + socket_name, strerror (errno)); + goto error; + } + + sock->watch = NIH_MUST (nih_io_add_watch (sock, sock->sock, + NIH_IO_READ, + (NihIoWatcher)socket_watcher, sock)); + + return sock; + +error: + nih_free (sock); + return NULL; +} + +static void +emit_event_error (void *data, + NihDBusMessage *message) +{ + NihError *err; + + err = nih_error_get (); + nih_warn ("%s", err->message); + nih_free (err); +}
-- upstart-devel mailing list [email protected] Modify settings or unsubscribe at: https://lists.ubuntu.com/mailman/listinfo/upstart-devel
