| /* upstart |
| * |
| * Copyright © 2010 Canonical Ltd. |
| * Author: Scott James Remnant <scott@netsplit.com>. |
| * |
| * 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 <dbus/dbus.h> |
| |
| #include <sys/types.h> |
| |
| #include <stdio.h> |
| #include <stdlib.h> |
| #include <unistd.h> |
| |
| #include <nih/macros.h> |
| #include <nih/alloc.h> |
| #include <nih/string.h> |
| #include <nih/main.h> |
| #include <nih/option.h> |
| #include <nih/command.h> |
| #include <nih/logging.h> |
| #include <nih/error.h> |
| #include <nih/hash.h> |
| #include <nih/tree.h> |
| |
| #include <nih-dbus/dbus_error.h> |
| #include <nih-dbus/dbus_proxy.h> |
| #include <nih-dbus/errors.h> |
| |
| #include "dbus/upstart.h" |
| |
| #include "com.ubuntu.Upstart.h" |
| #include "com.ubuntu.Upstart.Job.h" |
| #include "com.ubuntu.Upstart.Instance.h" |
| |
| #include "../init/events.h" |
| #include "initctl.h" |
| |
| |
| /* Prototypes for local functions */ |
| NihDBusProxy *upstart_open (const void *parent) |
| __attribute__ ((warn_unused_result, malloc)); |
| char * job_status (const void *parent, |
| NihDBusProxy *job_class, NihDBusProxy *job) |
| __attribute__ ((warn_unused_result, malloc)); |
| |
| /* Prototypes for static functions */ |
| static void start_reply_handler (char **job_path, NihDBusMessage *message, |
| const char *instance); |
| static void reply_handler (int *ret, NihDBusMessage *message); |
| static void error_handler (void *data, NihDBusMessage *message); |
| |
| static void job_class_condition_handler (void *data, |
| NihDBusMessage *message, |
| char ** const *value); |
| |
| static void job_class_condition_err_handler (void *data, |
| NihDBusMessage *message); |
| |
| static void job_class_parse_events (const ConditionHandlerData *data, |
| char ** const *variant_array); |
| |
| static void job_class_show_emits (const void *parent, |
| NihDBusProxy *job_class_proxy, const char *job_class_name); |
| |
| static void job_class_show_conditions (NihDBusProxy *job_class_proxy, |
| const char *job_class_name); |
| |
| #ifndef TEST |
| |
| static int dbus_bus_type_setter (NihOption *option, const char *arg); |
| |
| #endif |
| |
| /* Prototypes for option and command functions */ |
| int start_action (NihCommand *command, char * const *args); |
| int stop_action (NihCommand *command, char * const *args); |
| int restart_action (NihCommand *command, char * const *args); |
| int reload_action (NihCommand *command, char * const *args); |
| int status_action (NihCommand *command, char * const *args); |
| int list_action (NihCommand *command, char * const *args); |
| int emit_action (NihCommand *command, char * const *args); |
| int reload_configuration_action (NihCommand *command, char * const *args); |
| int version_action (NihCommand *command, char * const *args); |
| int log_priority_action (NihCommand *command, char * const *args); |
| int show_config_action (NihCommand *command, char * const *args); |
| |
| |
| /** |
| * use_dbus: |
| * |
| * If 1, connect using a D-Bus bus. |
| * If 0, connect using private connection. |
| * If -1, determine appropriate connection based on UID. |
| */ |
| int use_dbus = -1; |
| |
| /** |
| * dbus_bus_type: |
| * |
| * D-Bus bus to connect to (DBUS_BUS_SYSTEM or DBUS_BUS_SESSION), or -1 |
| * to have an appropriate bus selected. |
| */ |
| int dbus_bus_type = -1; |
| |
| /** |
| * dest_name: |
| * |
| * Name on the D-Bus system bus that the message should be sent to when |
| * system is TRUE. |
| **/ |
| char *dest_name = NULL; |
| |
| /** |
| * dest_address: |
| * |
| * Address for private D-Bus connection. |
| **/ |
| const char *dest_address = DBUS_ADDRESS_UPSTART; |
| |
| /** |
| * no_wait: |
| * |
| * Whether to wait for a job or event to be finished before existing or not. |
| **/ |
| int no_wait = FALSE; |
| |
| /** |
| * enumerate_events: |
| * |
| * If TRUE, list out all events/jobs that a particular job *may require* to |
| * be run: essentially any event/job mentioned in a job configuration files |
| * "start on" / "stop on" condition. Used for showing dependencies |
| * between jobs and events. |
| **/ |
| int enumerate_events = FALSE; |
| |
| /** |
| * NihOption setter function to handle selection of appropriate D-Bus |
| * bus. |
| * |
| * Always returns 1 denoting success. |
| **/ |
| int |
| dbus_bus_type_setter (NihOption *option, const char *arg) |
| { |
| nih_assert (option); |
| |
| if (! strcmp (option->long_option, "system")) { |
| use_dbus = TRUE; |
| dbus_bus_type = DBUS_BUS_SYSTEM; |
| } |
| else if (! strcmp (option->long_option, "session")) { |
| use_dbus = TRUE; |
| dbus_bus_type = DBUS_BUS_SESSION; |
| } |
| |
| return 1; |
| } |
| |
| /** |
| * upstart_open: |
| * @parent: parent object for new proxy. |
| * |
| * Opens a connection to the init daemon and returns a proxy to the manager |
| * object. If @dest_name is not NULL, a connection is instead opened to |
| * the system bus and the proxy linked to the well-known name given. |
| * |
| * Error messages are output to standard error. |
| * |
| * If @parent is not NULL, it should be a pointer to another object which |
| * will be used as a parent for the returned proxy. When all parents |
| * of the returned proxy are freed, the returned proxy will also be |
| * freed. |
| * |
| * Returns: newly allocated D-Bus proxy or NULL on error. |
| **/ |
| NihDBusProxy * |
| upstart_open (const void *parent) |
| { |
| DBusError dbus_error; |
| DBusConnection *connection; |
| NihDBusProxy * upstart; |
| |
| if (use_dbus < 0) |
| use_dbus = getuid () ? TRUE : FALSE; |
| if (use_dbus >= 0 && dbus_bus_type < 0) |
| dbus_bus_type = DBUS_BUS_SYSTEM; |
| |
| dbus_error_init (&dbus_error); |
| if (use_dbus) { |
| if (! dest_name) |
| dest_name = DBUS_SERVICE_UPSTART; |
| |
| connection = dbus_bus_get (dbus_bus_type, &dbus_error); |
| if (! connection) { |
| nih_error ("%s: %s", |
| dbus_bus_type == DBUS_BUS_SYSTEM |
| ? _("Unable to connect to system bus") |
| : _("Unable to connect to session bus"), |
| dbus_error.message); |
| dbus_error_free (&dbus_error); |
| return NULL; |
| } |
| |
| dbus_connection_set_exit_on_disconnect (connection, FALSE); |
| } else { |
| if (dest_name) { |
| fprintf (stderr, _("%s: --dest given without --system\n"), |
| program_name); |
| nih_main_suggest_help (); |
| return NULL; |
| } |
| |
| connection = dbus_connection_open (dest_address, &dbus_error); |
| if (! connection) { |
| nih_error ("%s: %s", _("Unable to connect to Upstart"), |
| dbus_error.message); |
| dbus_error_free (&dbus_error); |
| return NULL; |
| } |
| } |
| dbus_error_free (&dbus_error); |
| |
| upstart = nih_dbus_proxy_new (parent, connection, |
| dest_name, |
| DBUS_PATH_UPSTART, |
| NULL, NULL); |
| if (! upstart) { |
| NihError *err; |
| |
| err = nih_error_get (); |
| nih_error ("%s", err->message); |
| nih_free (err); |
| |
| dbus_connection_unref (connection); |
| return NULL; |
| } |
| |
| upstart->auto_start = FALSE; |
| |
| /* Drop initial reference now the proxy holds one */ |
| dbus_connection_unref (connection); |
| |
| return upstart; |
| } |
| |
| |
| /** |
| * job_status: |
| * @parent: parent object for new string, |
| * @job_class: proxy for remote job class object, |
| * @job: proxy for remote instance object. |
| * |
| * Queries the job object @job and contructs a string defining the status |
| * of that instance, containing the name of the @job_class and @job, |
| * the goal, state and any running processes. |
| * |
| * @job may be NULL in which case a non-running job is assumed, the |
| * function also catches the remote object no longer existing. |
| * |
| * If @parent is not NULL, it should be a pointer to another object which |
| * will be used as a parent for the returned string. When all parents |
| * of the returned string are freed, the returned string will also be |
| * freed. |
| * |
| * Returns: newly allocated string or NULL on raised error. |
| **/ |
| char * |
| job_status (const void * parent, |
| NihDBusProxy *job_class, |
| NihDBusProxy *job) |
| { |
| nih_local char * job_class_name = NULL; |
| nih_local JobProperties *props = NULL; |
| char * str = NULL; |
| |
| nih_assert (job_class != NULL); |
| |
| /* Get the job name */ |
| if (job_class_get_name_sync (NULL, job_class, &job_class_name) < 0) |
| return NULL; |
| |
| /* Get the instance properties, catching the instance going away |
| * between the time we got it and this call. |
| */ |
| if (job) { |
| if (job_get_all_sync (NULL, job, &props) < 0) { |
| NihDBusError *dbus_err; |
| |
| dbus_err = (NihDBusError *)nih_error_get (); |
| if ((dbus_err->number != NIH_DBUS_ERROR) |
| || strcmp (dbus_err->name, DBUS_ERROR_UNKNOWN_METHOD)) { |
| return NULL; |
| } else { |
| nih_free (dbus_err); |
| } |
| } |
| } |
| |
| if (props && *props->name) { |
| str = nih_sprintf (parent, "%s (%s)", |
| job_class_name, props->name); |
| if (! str) |
| nih_return_no_memory_error (NULL); |
| } else { |
| str = nih_strdup (parent, job_class_name); |
| if (! str) |
| nih_return_no_memory_error (NULL); |
| } |
| |
| if (props) { |
| if (! nih_strcat_sprintf (&str, parent, " %s/%s", |
| props->goal, props->state)) { |
| nih_error_raise_no_memory (); |
| nih_free (str); |
| return NULL; |
| } |
| |
| /* The first process returned is always the main process, |
| * which is the process we always want to display alongside |
| * the state if there is one. Prefix if it's not one of |
| * the standard processes. |
| */ |
| if (props->processes[0]) { |
| if (strcmp (props->processes[0]->item0, "main") |
| && strcmp (props->processes[0]->item0, "pre-start") |
| && strcmp (props->processes[0]->item0, "post-stop")) { |
| if (! nih_strcat_sprintf (&str, parent, ", (%s) process %d", |
| props->processes[0]->item0, |
| props->processes[0]->item1)) { |
| nih_error_raise_no_memory (); |
| nih_free (str); |
| return NULL; |
| } |
| } else { |
| if (! nih_strcat_sprintf (&str, parent, ", process %d", |
| props->processes[0]->item1)) { |
| nih_error_raise_no_memory (); |
| nih_free (str); |
| return NULL; |
| } |
| } |
| |
| /* Append a line for each additional process */ |
| for (JobProcessesElement **p = &props->processes[1]; |
| p && *p; p++) { |
| if (! nih_strcat_sprintf (&str, parent, "\n\t%s process %d", |
| (*p)->item0, |
| (*p)->item1)) { |
| nih_error_raise_no_memory (); |
| nih_free (str); |
| return NULL; |
| } |
| } |
| } |
| } else { |
| if (! nih_strcat (&str, parent, " stop/waiting")) { |
| nih_error_raise_no_memory (); |
| nih_free (str); |
| return NULL; |
| } |
| } |
| |
| return str; |
| } |
| |
| |
| /** |
| * start_action: |
| * @command: NihCommand invoked, |
| * @args: command-line arguments. |
| * |
| * This function is called for the "start" command. |
| * |
| * Returns: command exit status. |
| **/ |
| int |
| start_action (NihCommand * command, |
| char * const *args) |
| { |
| nih_local NihDBusProxy *upstart = NULL; |
| const char * upstart_job = NULL; |
| const char * upstart_instance = NULL; |
| nih_local char * job_class_path = NULL; |
| nih_local NihDBusProxy *job_class = NULL; |
| nih_local char * job_path = NULL; |
| nih_local NihDBusProxy *job = NULL; |
| DBusPendingCall * pending_call; |
| int ret = 1; |
| NihError * err; |
| |
| nih_assert (command != NULL); |
| nih_assert (args != NULL); |
| |
| if (args[0]) { |
| upstart_job = args[0]; |
| } else { |
| upstart_job = getenv ("UPSTART_JOB"); |
| upstart_instance = getenv ("UPSTART_INSTANCE"); |
| |
| if (! (upstart_job && upstart_instance)) { |
| fprintf (stderr, _("%s: missing job name\n"), program_name); |
| nih_main_suggest_help (); |
| return 1; |
| } |
| } |
| |
| upstart = upstart_open (NULL); |
| if (! upstart) |
| return 1; |
| |
| /* Obtain a proxy to the job */ |
| if (upstart_get_job_by_name_sync (NULL, upstart, upstart_job, |
| &job_class_path) < 0) |
| goto error; |
| |
| job_class = nih_dbus_proxy_new (NULL, upstart->connection, |
| upstart->name, job_class_path, |
| NULL, NULL); |
| if (! job_class) |
| goto error; |
| |
| job_class->auto_start = FALSE; |
| |
| /* When called from a job handler, we directly change the goal |
| * so we need the instance. These calls are always made without |
| * waiting, since otherwise we'd block the job we're called from. |
| */ |
| if (upstart_instance) { |
| if (job_class_get_instance_by_name_sync (NULL, job_class, |
| upstart_instance, |
| &job_path) < 0) |
| goto error; |
| |
| job = nih_dbus_proxy_new (NULL, upstart->connection, |
| upstart->name, job_path, |
| NULL, NULL); |
| if (! job) |
| goto error; |
| |
| job->auto_start = FALSE; |
| |
| pending_call = job_start (job, FALSE, |
| (JobStartReply)reply_handler, |
| error_handler, &ret, |
| NIH_DBUS_TIMEOUT_NEVER); |
| if (! pending_call) |
| goto error; |
| } else { |
| /* job_path is nih_local, so whatever gets filled in will |
| * be automatically freed. |
| */ |
| pending_call = job_class_start (job_class, &args[1], (! no_wait), |
| (JobClassStartReply)start_reply_handler, |
| error_handler, &job_path, |
| NIH_DBUS_TIMEOUT_NEVER); |
| if (! pending_call) |
| goto error; |
| } |
| |
| dbus_pending_call_block (pending_call); |
| dbus_pending_call_unref (pending_call); |
| |
| /* Make sure we got a valid job path, and in the case of the instance |
| * path, no error message. Then display the current job status. |
| */ |
| if (job_path && ((job == NULL) || (ret == 0))) { |
| nih_local char *status = NULL; |
| |
| if (! job) { |
| job = NIH_SHOULD (nih_dbus_proxy_new ( |
| NULL, upstart->connection, |
| upstart->name, job_path, |
| NULL, NULL)); |
| if (! job) |
| goto error; |
| |
| job->auto_start = FALSE; |
| } |
| |
| status = NIH_SHOULD (job_status (NULL, job_class, job)); |
| if (! status) |
| goto error; |
| |
| nih_message ("%s", status); |
| |
| ret = 0; |
| } else { |
| ret = 1; |
| } |
| |
| return ret; |
| |
| error: |
| err = nih_error_get (); |
| nih_error ("%s", err->message); |
| nih_free (err); |
| |
| return 1; |
| } |
| |
| |
| /** |
| * stop_action: |
| * @command: NihCommand invoked, |
| * @args: command-line arguments. |
| * |
| * This function is called for the "stop" command. |
| * |
| * Returns: command exit status. |
| **/ |
| int |
| stop_action (NihCommand * command, |
| char * const *args) |
| { |
| nih_local NihDBusProxy *upstart = NULL; |
| const char * upstart_job = NULL; |
| const char * upstart_instance = NULL; |
| nih_local char * job_class_path = NULL; |
| nih_local NihDBusProxy *job_class = NULL; |
| nih_local char * job_path = NULL; |
| nih_local NihDBusProxy *job = NULL; |
| DBusPendingCall * pending_call; |
| int ret = 1; |
| NihError * err; |
| |
| nih_assert (command != NULL); |
| nih_assert (args != NULL); |
| |
| if (args[0]) { |
| upstart_job = args[0]; |
| } else { |
| upstart_job = getenv ("UPSTART_JOB"); |
| upstart_instance = getenv ("UPSTART_INSTANCE"); |
| |
| if (! (upstart_job && upstart_instance)) { |
| fprintf (stderr, _("%s: missing job name\n"), program_name); |
| nih_main_suggest_help (); |
| return 1; |
| } |
| } |
| |
| upstart = upstart_open (NULL); |
| if (! upstart) |
| return 1; |
| |
| /* Obtain a proxy to the job */ |
| if (upstart_get_job_by_name_sync (NULL, upstart, upstart_job, |
| &job_class_path) < 0) |
| goto error; |
| |
| job_class = nih_dbus_proxy_new (NULL, upstart->connection, |
| upstart->name, job_class_path, |
| NULL, NULL); |
| if (! job_class) |
| goto error; |
| |
| job_class->auto_start = FALSE; |
| |
| /* When called from a job handler, we directly change the goal |
| * so need the instance. These calls are always made without |
| * waiting, since otherwise we'd block the job we're called from. |
| */ |
| if (upstart_instance) { |
| if (job_class_get_instance_by_name_sync (NULL, job_class, |
| upstart_instance, |
| &job_path) < 0) |
| goto error; |
| |
| job = nih_dbus_proxy_new (NULL, upstart->connection, |
| upstart->name, job_path, |
| NULL, NULL); |
| if (! job) |
| goto error; |
| |
| job->auto_start = FALSE; |
| |
| pending_call = job_stop (job, FALSE, |
| (JobStopReply)reply_handler, |
| error_handler, &ret, |
| NIH_DBUS_TIMEOUT_NEVER); |
| if (! pending_call) |
| goto error; |
| } else { |
| /* Lookup the instance that we'll end up stopping */ |
| if (job_class_get_instance_sync (NULL, job_class, &args[1], |
| &job_path) < 0) |
| goto error; |
| |
| job = nih_dbus_proxy_new (NULL, upstart->connection, |
| upstart->name, job_path, |
| NULL, NULL); |
| if (! job) |
| goto error; |
| |
| job->auto_start = FALSE; |
| |
| pending_call = job_class_stop (job_class, &args[1], (! no_wait), |
| (JobClassStopReply)reply_handler, |
| error_handler, &ret, |
| NIH_DBUS_TIMEOUT_NEVER); |
| if (! pending_call) |
| goto error; |
| } |
| |
| dbus_pending_call_block (pending_call); |
| dbus_pending_call_unref (pending_call); |
| |
| /* Display the current job status */ |
| if (ret == 0) { |
| nih_local char *status = NULL; |
| |
| status = NIH_SHOULD (job_status (NULL, job_class, job)); |
| if (! status) |
| goto error; |
| |
| nih_message ("%s", status); |
| } |
| |
| return ret; |
| |
| error: |
| err = nih_error_get (); |
| nih_error ("%s", err->message); |
| nih_free (err); |
| |
| return 1; |
| } |
| |
| |
| /** |
| * restart_action: |
| * @command: NihCommand invoked, |
| * @args: command-line arguments. |
| * |
| * This function is called for the "restart" command. |
| * |
| * Returns: command exit status. |
| **/ |
| int |
| restart_action (NihCommand * command, |
| char * const *args) |
| { |
| nih_local NihDBusProxy *upstart = NULL; |
| const char * upstart_job = NULL; |
| const char * upstart_instance = NULL; |
| nih_local char * job_class_path = NULL; |
| nih_local NihDBusProxy *job_class = NULL; |
| nih_local char * job_path = NULL; |
| nih_local NihDBusProxy *job = NULL; |
| DBusPendingCall * pending_call; |
| int ret = 1; |
| NihError * err; |
| |
| nih_assert (command != NULL); |
| nih_assert (args != NULL); |
| |
| if (args[0]) { |
| upstart_job = args[0]; |
| } else { |
| upstart_job = getenv ("UPSTART_JOB"); |
| upstart_instance = getenv ("UPSTART_INSTANCE"); |
| |
| if (! (upstart_job && upstart_instance)) { |
| fprintf (stderr, _("%s: missing job name\n"), program_name); |
| nih_main_suggest_help (); |
| return 1; |
| } |
| } |
| |
| upstart = upstart_open (NULL); |
| if (! upstart) |
| return 1; |
| |
| /* Obtain a proxy to the job */ |
| if (upstart_get_job_by_name_sync (NULL, upstart, upstart_job, |
| &job_class_path) < 0) |
| goto error; |
| |
| job_class = nih_dbus_proxy_new (NULL, upstart->connection, |
| upstart->name, job_class_path, |
| NULL, NULL); |
| if (! job_class) |
| goto error; |
| |
| job_class->auto_start = FALSE; |
| |
| /* When called from a job handler, we directly toggle the goal |
| * so we need the instance. These calls are always made without |
| * waiting, since otherwise we'd block the job we're called from. |
| */ |
| if (upstart_instance) { |
| if (job_class_get_instance_by_name_sync (NULL, job_class, |
| upstart_instance, |
| &job_path) < 0) |
| goto error; |
| |
| job = nih_dbus_proxy_new (NULL, upstart->connection, |
| upstart->name, job_path, |
| NULL, NULL); |
| if (! job) |
| goto error; |
| |
| job->auto_start = FALSE; |
| |
| pending_call = job_restart (job, FALSE, |
| (JobRestartReply)reply_handler, |
| error_handler, &ret, |
| NIH_DBUS_TIMEOUT_NEVER); |
| if (! pending_call) |
| goto error; |
| } else { |
| /* job_path is nih_local, so whatever gets filled in will |
| * be automatically freed. |
| */ |
| pending_call = job_class_restart (job_class, &args[1], (! no_wait), |
| (JobClassRestartReply)start_reply_handler, |
| error_handler, &job_path, |
| NIH_DBUS_TIMEOUT_NEVER); |
| |
| if (! pending_call) |
| goto error; |
| } |
| |
| dbus_pending_call_block (pending_call); |
| dbus_pending_call_unref (pending_call); |
| |
| /* Make sure we got a valid job path, and in the case of the instance |
| * path, no error message. Then display the current job status. |
| */ |
| if (job_path && ((job == NULL) || (ret == 0))) { |
| nih_local char *status = NULL; |
| |
| if (! job) { |
| job = NIH_SHOULD (nih_dbus_proxy_new ( |
| NULL, upstart->connection, |
| upstart->name, job_path, |
| NULL, NULL)); |
| if (! job) |
| goto error; |
| |
| job->auto_start = FALSE; |
| } |
| |
| status = NIH_SHOULD (job_status (NULL, job_class, job)); |
| if (! status) |
| goto error; |
| |
| nih_message ("%s", status); |
| |
| ret = 0; |
| } else { |
| ret = 1; |
| } |
| |
| return ret; |
| |
| error: |
| err = nih_error_get (); |
| nih_error ("%s", err->message); |
| nih_free (err); |
| |
| return 1; |
| } |
| |
| |
| /** |
| * reload_action: |
| * @command: NihCommand invoked, |
| * @args: command-line arguments. |
| * |
| * This function is called for the "reload" command. |
| * |
| * Returns: command exit status. |
| **/ |
| int |
| reload_action (NihCommand * command, |
| char * const *args) |
| { |
| nih_local NihDBusProxy *upstart = NULL; |
| const char * upstart_job = NULL; |
| const char * upstart_instance = NULL; |
| nih_local char * job_class_path = NULL; |
| nih_local NihDBusProxy *job_class = NULL; |
| nih_local char * job_path = NULL; |
| nih_local NihDBusProxy *job = NULL; |
| nih_local JobProcessesElement **processes = NULL; |
| NihError * err; |
| |
| nih_assert (command != NULL); |
| nih_assert (args != NULL); |
| |
| if (args[0]) { |
| upstart_job = args[0]; |
| } else { |
| upstart_job = getenv ("UPSTART_JOB"); |
| upstart_instance = getenv ("UPSTART_INSTANCE"); |
| |
| if (! (upstart_job && upstart_instance)) { |
| fprintf (stderr, _("%s: missing job name\n"), program_name); |
| nih_main_suggest_help (); |
| return 1; |
| } |
| } |
| |
| upstart = upstart_open (NULL); |
| if (! upstart) |
| return 1; |
| |
| /* Obtain a proxy to the job */ |
| if (upstart_get_job_by_name_sync (NULL, upstart, upstart_job, |
| &job_class_path) < 0) |
| goto error; |
| |
| job_class = nih_dbus_proxy_new (NULL, upstart->connection, |
| upstart->name, job_class_path, |
| NULL, NULL); |
| if (! job_class) |
| goto error; |
| |
| job_class->auto_start = FALSE; |
| |
| /* Obtain a proxy to the specific instance. Catch the case where |
| * we were just given a job name, and there was no single instance |
| * running. |
| */ |
| if (upstart_instance) { |
| if (job_class_get_instance_by_name_sync (NULL, job_class, |
| upstart_instance, |
| &job_path) < 0) |
| goto error; |
| } else { |
| if (job_class_get_instance_sync (NULL, job_class, |
| &args[1], &job_path) < 0) |
| goto error; |
| } |
| |
| job = nih_dbus_proxy_new (NULL, upstart->connection, |
| upstart->name, job_path, |
| NULL, NULL); |
| if (! job) |
| goto error; |
| |
| job->auto_start = FALSE; |
| |
| /* Get the process list */ |
| if (job_get_processes_sync (NULL, job, &processes) < 0) |
| goto error; |
| |
| if ((! processes[0]) || strcmp (processes[0]->item0, "main")) { |
| nih_error (_("Not running")); |
| return 1; |
| } |
| |
| if (kill (processes[0]->item1, SIGHUP) < 0) { |
| nih_error_raise_system (); |
| goto error; |
| } |
| |
| return 0; |
| |
| error: |
| err = nih_error_get (); |
| nih_error ("%s", err->message); |
| nih_free (err); |
| |
| return 1; |
| } |
| |
| |
| /** |
| * status_action: |
| * @command: NihCommand invoked, |
| * @args: command-line arguments. |
| * |
| * This function is called for the "status" command. |
| * |
| * Returns: command exit status. |
| **/ |
| int |
| status_action (NihCommand * command, |
| char * const *args) |
| { |
| nih_local NihDBusProxy *upstart = NULL; |
| const char * upstart_job = NULL; |
| const char * upstart_instance = NULL; |
| nih_local char * job_class_path = NULL; |
| nih_local NihDBusProxy *job_class = NULL; |
| nih_local char * job_path = NULL; |
| nih_local NihDBusProxy *job = NULL; |
| nih_local char * status = NULL; |
| NihError * err; |
| NihDBusError * dbus_err; |
| |
| nih_assert (command != NULL); |
| nih_assert (args != NULL); |
| |
| if (args[0]) { |
| upstart_job = args[0]; |
| } else { |
| upstart_job = getenv ("UPSTART_JOB"); |
| upstart_instance = getenv ("UPSTART_INSTANCE"); |
| |
| if (! (upstart_job && upstart_instance)) { |
| fprintf (stderr, _("%s: missing job name\n"), program_name); |
| nih_main_suggest_help (); |
| return 1; |
| } |
| } |
| |
| upstart = upstart_open (NULL); |
| if (! upstart) |
| return 1; |
| |
| /* Obtain a proxy to the job */ |
| if (upstart_get_job_by_name_sync (NULL, upstart, upstart_job, |
| &job_class_path) < 0) |
| goto error; |
| |
| job_class = nih_dbus_proxy_new (NULL, upstart->connection, |
| upstart->name, job_class_path, |
| NULL, NULL); |
| if (! job_class) |
| goto error; |
| |
| job_class->auto_start = FALSE; |
| |
| /* Obtain a proxy to the specific instance. Catch the case where |
| * we were just given a job name, and there was no single instance |
| * running. |
| */ |
| if (upstart_instance) { |
| if (job_class_get_instance_by_name_sync (NULL, job_class, |
| upstart_instance, |
| &job_path) < 0) |
| goto error; |
| } else { |
| if (job_class_get_instance_sync (NULL, job_class, |
| &args[1], &job_path) < 0) { |
| dbus_err = (NihDBusError *)nih_error_get (); |
| if (args[1] |
| || (dbus_err->number != NIH_DBUS_ERROR) |
| || strcmp (dbus_err->name, DBUS_INTERFACE_UPSTART ".Error.UnknownInstance")) |
| goto error; |
| |
| nih_free (dbus_err); |
| } |
| } |
| |
| if (job_path) { |
| job = nih_dbus_proxy_new (NULL, upstart->connection, |
| upstart->name, job_path, |
| NULL, NULL); |
| if (! job) |
| goto error; |
| |
| job->auto_start = FALSE; |
| } else { |
| job = NULL; |
| } |
| |
| status = job_status (NULL, job_class, job); |
| if (! status) |
| goto error; |
| |
| nih_message ("%s", status); |
| |
| return 0; |
| |
| error: |
| err = nih_error_get (); |
| nih_error ("%s", err->message); |
| nih_free (err); |
| |
| return 1; |
| } |
| |
| |
| /** |
| * list_action: |
| * @command: NihCommand invoked, |
| * @args: command-line arguments. |
| * |
| * This function is called for the "list" command. |
| * |
| * Returns: command exit status. |
| **/ |
| int |
| list_action (NihCommand * command, |
| char * const *args) |
| { |
| nih_local NihDBusProxy *upstart = NULL; |
| nih_local char ** job_class_paths = NULL; |
| NihError * err; |
| NihDBusError * dbus_err; |
| |
| nih_assert (command != NULL); |
| nih_assert (args != NULL); |
| |
| upstart = upstart_open (NULL); |
| if (! upstart) |
| return 1; |
| |
| /* Obtain a list of jobs */ |
| if (upstart_get_all_jobs_sync (NULL, upstart, &job_class_paths) < 0) |
| goto error; |
| |
| for (char **job_class_path = job_class_paths; |
| job_class_path && *job_class_path; job_class_path++) { |
| nih_local NihDBusProxy *job_class = NULL; |
| nih_local char ** job_paths = NULL; |
| |
| job_class = nih_dbus_proxy_new (NULL, upstart->connection, |
| upstart->name, *job_class_path, |
| NULL, NULL); |
| if (! job_class) |
| goto error; |
| |
| job_class->auto_start = FALSE; |
| |
| /* Obtain a list of instances, catch an error from the |
| * command and assume the job just went away. |
| */ |
| if (job_class_get_all_instances_sync (NULL, job_class, |
| &job_paths) < 0) { |
| dbus_err = (NihDBusError *)nih_error_get (); |
| if ((dbus_err->number != NIH_DBUS_ERROR) |
| || strcmp (dbus_err->name, DBUS_ERROR_UNKNOWN_METHOD)) |
| goto error; |
| |
| nih_free (dbus_err); |
| continue; |
| } |
| |
| /* Handle no running instances by assuming that the |
| * job is just stopped, again catch an error and assume |
| * the job went away. |
| */ |
| if (! *job_paths) { |
| nih_local char *status = NULL; |
| |
| status = job_status (NULL, job_class, NULL); |
| if (! status) { |
| dbus_err = (NihDBusError *)nih_error_get (); |
| if ((dbus_err->number != NIH_DBUS_ERROR) |
| || strcmp (dbus_err->name, DBUS_ERROR_UNKNOWN_METHOD)) |
| goto error; |
| |
| nih_free (dbus_err); |
| continue; |
| } |
| |
| nih_message ("%s", status); |
| } |
| |
| /* Otherwise iterate the instances and output the status |
| * of each. |
| */ |
| for (char **job_path = job_paths; job_path && *job_path; |
| job_path++) { |
| nih_local NihDBusProxy *job = NULL; |
| nih_local char * status = NULL; |
| |
| job = nih_dbus_proxy_new (NULL, upstart->connection, |
| upstart->name, *job_path, |
| NULL, NULL); |
| if (! job) |
| goto error; |
| |
| job->auto_start = FALSE; |
| |
| status = job_status (NULL, job_class, job); |
| if (! status) { |
| dbus_err = (NihDBusError *)nih_error_get (); |
| if ((dbus_err->number != NIH_DBUS_ERROR) |
| || strcmp (dbus_err->name, DBUS_ERROR_UNKNOWN_METHOD)) |
| goto error; |
| |
| nih_free (dbus_err); |
| continue; |
| } |
| |
| nih_message ("%s", status); |
| } |
| } |
| |
| return 0; |
| |
| error: |
| err = nih_error_get (); |
| nih_error ("%s", err->message); |
| nih_free (err); |
| |
| return 1; |
| } |
| |
| /** |
| * show_config_action: |
| * @command: NihCommand invoked, |
| * @args: command-line arguments. |
| * |
| * This function is called for the "show-config" command. |
| * |
| * Returns: command exit status. |
| **/ |
| int |
| show_config_action (NihCommand * command, |
| char * const *args) |
| { |
| nih_local NihDBusProxy *upstart = NULL; |
| nih_local char **job_class_paths = NULL; |
| const char *upstart_job_class = NULL; |
| NihError *err; |
| |
| nih_assert (command != NULL); |
| nih_assert (args != NULL); |
| |
| upstart = upstart_open (NULL); |
| if (! upstart) |
| return 1; |
| |
| if (args[0]) { |
| /* Single job specified */ |
| upstart_job_class = args[0]; |
| job_class_paths = NIH_MUST (nih_alloc (NULL, 2*sizeof (char *))); |
| job_class_paths[1] = NULL; |
| |
| if (upstart_get_job_by_name_sync (NULL, upstart, upstart_job_class, |
| job_class_paths) < 0) |
| goto error; |
| } else { |
| /* Obtain a list of jobs */ |
| if (upstart_get_all_jobs_sync (NULL, upstart, &job_class_paths) < 0) |
| goto error; |
| } |
| |
| for (char **job_class_path = job_class_paths; |
| job_class_path && *job_class_path; job_class_path++) { |
| nih_local NihDBusProxy *job_class = NULL; |
| nih_local char *job_class_name = NULL; |
| |
| job_class = nih_dbus_proxy_new (NULL, upstart->connection, |
| upstart->name, *job_class_path, |
| NULL, NULL); |
| if (! job_class) |
| goto error; |
| |
| job_class->auto_start = FALSE; |
| |
| if (job_class_get_name_sync (NULL, job_class, &job_class_name) < 0) |
| goto error; |
| |
| nih_message ("%s", job_class_name); |
| |
| job_class_show_emits (NULL, job_class, job_class_name); |
| job_class_show_conditions (job_class, job_class_name); |
| } |
| |
| return 0; |
| |
| error: |
| err = nih_error_get (); |
| nih_error ("%s", err->message); |
| nih_free (err); |
| |
| return 1; |
| } |
| |
| /** |
| * emit_action: |
| * @command: NihCommand invoked, |
| * @args: command-line arguments. |
| * |
| * This function is called for the "emit" command. |
| * |
| * Returns: command exit status. |
| **/ |
| int |
| emit_action (NihCommand * command, |
| char * const *args) |
| { |
| nih_local NihDBusProxy *upstart = NULL; |
| DBusPendingCall * pending_call; |
| int ret = 1; |
| NihError * err; |
| |
| nih_assert (command != NULL); |
| nih_assert (args != NULL); |
| |
| if (! args[0]) { |
| fprintf (stderr, _("%s: missing event name\n"), program_name); |
| nih_main_suggest_help (); |
| return 1; |
| } |
| |
| upstart = upstart_open (NULL); |
| if (! upstart) |
| return 1; |
| |
| pending_call = upstart_emit_event (upstart, args[0], &args[1], (! no_wait), |
| (UpstartEmitEventReply)reply_handler, |
| error_handler, &ret, |
| NIH_DBUS_TIMEOUT_NEVER); |
| if (! pending_call) |
| goto error; |
| |
| dbus_pending_call_block (pending_call); |
| dbus_pending_call_unref (pending_call); |
| |
| return ret; |
| |
| error: |
| err = nih_error_get (); |
| nih_error ("%s", err->message); |
| nih_free (err); |
| |
| return 1; |
| } |
| |
| |
| /** |
| * reload_configuration_action: |
| * @command: NihCommand invoked, |
| * @args: command-line arguments. |
| * |
| * This function is called for the "reload-configuration" command. |
| * |
| * Returns: command exit status. |
| **/ |
| int |
| reload_configuration_action (NihCommand * command, |
| char * const *args) |
| { |
| nih_local NihDBusProxy *upstart = NULL; |
| NihError * err; |
| |
| nih_assert (command != NULL); |
| nih_assert (args != NULL); |
| |
| upstart = upstart_open (NULL); |
| if (! upstart) |
| return 1; |
| |
| if (upstart_reload_configuration_sync (NULL, upstart) < 0) |
| goto error; |
| |
| return 0; |
| |
| error: |
| err = nih_error_get (); |
| nih_error ("%s", err->message); |
| nih_free (err); |
| |
| return 1; |
| } |
| |
| |
| /** |
| * version_action: |
| * @command: NihCommand invoked, |
| * @args: command-line arguments. |
| * |
| * This function is called for the "version" command. |
| * |
| * Returns: command exit status. |
| **/ |
| int |
| version_action (NihCommand * command, |
| char * const *args) |
| { |
| nih_local NihDBusProxy *upstart = NULL; |
| nih_local char * version = NULL; |
| NihError * err; |
| |
| nih_assert (command != NULL); |
| nih_assert (args != NULL); |
| |
| upstart = upstart_open (NULL); |
| if (! upstart) |
| return 1; |
| |
| if (upstart_get_version_sync (NULL, upstart, &version) < 0) |
| goto error; |
| |
| nih_message ("%s", version); |
| |
| return 0; |
| |
| error: |
| err = nih_error_get (); |
| nih_error ("%s", err->message); |
| nih_free (err); |
| |
| return 1; |
| } |
| |
| |
| /** |
| * log_priority_action: |
| * @command: NihCommand invoked, |
| * @args: command-line arguments. |
| * |
| * This function is called for the "log-priority" command. |
| * |
| * Returns: command exit status. |
| **/ |
| int |
| log_priority_action (NihCommand * command, |
| char * const *args) |
| { |
| nih_local NihDBusProxy *upstart = NULL; |
| NihError * err; |
| |
| nih_assert (command != NULL); |
| nih_assert (args != NULL); |
| |
| upstart = upstart_open (NULL); |
| if (! upstart) |
| return 1; |
| |
| if (args[0]) { |
| if (upstart_set_log_priority_sync (NULL, upstart, args[0]) < 0) |
| goto error; |
| } else { |
| nih_local char *log_priority = NULL; |
| |
| if (upstart_get_log_priority_sync (NULL, upstart, |
| &log_priority) < 0) |
| goto error; |
| |
| nih_message ("%s", log_priority); |
| } |
| |
| return 0; |
| |
| error: |
| err = nih_error_get (); |
| nih_error ("%s", err->message); |
| nih_free (err); |
| |
| return 1; |
| } |
| |
| |
| static void |
| start_reply_handler (char ** job_path, |
| NihDBusMessage *message, |
| const char * instance) |
| { |
| nih_assert (message != NULL); |
| nih_assert (instance != NULL); |
| |
| /* Return the job path */ |
| *job_path = NIH_MUST (nih_strdup (NULL, instance)); |
| } |
| |
| static void |
| reply_handler (int * ret, |
| NihDBusMessage *message) |
| { |
| nih_assert (message != NULL); |
| |
| *ret = 0; |
| } |
| |
| static void |
| error_handler (void * data, |
| NihDBusMessage *message) |
| { |
| NihError *err; |
| |
| nih_assert (message != NULL); |
| |
| err = nih_error_get (); |
| nih_error ("%s", err->message); |
| nih_free (err); |
| } |
| |
| /** |
| * job_class_parse_events: |
| * @condition_data: type of condition we are parsing (used as an indicator to |
| * user) and name of job, |
| * @variant_array: pointer to array of variants. |
| * |
| * The array of variants encodes the event operator tree in |
| * Reverse Polish Notation (RPN). |
| * |
| * Each variant is itself an array. There are two types: |
| * |
| * - An "Operator" (array length == 1). |
| * |
| * Operators are: "/AND" and "/OR". |
| * |
| * - An "Event" (array length >= 1). |
| * |
| * Each Event comprises a name (array element zero), followed by zero or |
| * more "Event Matches". If the first Event Match is of the form "JOB=name", |
| * or is a single token "name" (crucially not containining "="), then |
| * 'name' refers to the job which emitted the event. |
| **/ |
| void |
| job_class_parse_events (const ConditionHandlerData *data, char ** const *variant_array) |
| { |
| char ** const *variant; |
| char **arg; |
| char *token; |
| nih_local NihList *rpn_stack = NULL; |
| char *name = NULL; |
| const char *stanza_name; |
| const char *job_class_name; |
| |
| nih_assert (data); |
| |
| stanza_name = ((ConditionHandlerData *)data)->condition_name; |
| job_class_name = ((ConditionHandlerData *)data)->job_class_name; |
| |
| if (! variant_array || ! *variant_array || ! **variant_array) |
| return; |
| |
| STACK_CREATE (rpn_stack); |
| STACK_SHOW (rpn_stack); |
| |
| for (variant = variant_array; variant && *variant && **variant; variant++, name = NULL) { |
| |
| /* token is either the first token beyond the stanza name (ie the event name), |
| * or an operator. |
| */ |
| token = **variant; |
| |
| if (IS_OPERATOR (token)) { |
| /* Used to hold result of combining top two stack elements. */ |
| nih_local char *new_token = NULL; |
| |
| nih_local NihList *first = NULL; |
| nih_local NihList *second = NULL; |
| |
| if (enumerate_events) { |
| /* We only care about operands in this mode. */ |
| continue; |
| } |
| |
| first = NIH_MUST (nih_list_new (NULL)); |
| second = NIH_MUST (nih_list_new (NULL)); |
| |
| /* Found an operator, so pop 2 values off stack, |
| * combine them and push back onto stack. |
| */ |
| STACK_POP (rpn_stack, first); |
| STACK_POP (rpn_stack, second); |
| |
| new_token = NIH_MUST (nih_strdup (NULL, "")); |
| new_token = NIH_MUST (nih_strcat_sprintf (&new_token, |
| NULL, |
| "(%s %s %s)", |
| ((NihListEntry *)second)->str, |
| IS_OP_AND (token) ? "and" : "or", |
| ((NihListEntry *)first)->str)); |
| |
| STACK_PUSH_NEW_ELEM (rpn_stack, new_token); |
| } else { |
| /* Save operand token (event or job), add |
| * arguments (job names and env vars) and push |
| * onto stack. If we are enumerating_events, |
| * this records the environment only. |
| */ |
| nih_local char *element = NULL; |
| int i; |
| |
| element = NIH_MUST (nih_strdup (NULL, |
| enumerate_events ? "" : token)); |
| |
| /* Handle arguments (job names and env vars). */ |
| arg = (*variant)+1; |
| |
| for (i=0; arg[i] && *arg[i]; i++) { |
| if (enumerate_events && IS_JOB_EVENT (token)) { |
| if (!name) { |
| GET_JOB_NAME (name, i, arg[i]); |
| if (name) |
| continue; |
| } |
| } |
| |
| element = NIH_MUST (nih_strcat (&element, NULL, " ")); |
| element = NIH_MUST (nih_strcat (&element, NULL, arg[i])); |
| } |
| |
| if (enumerate_events) { |
| nih_message (" %s %s (job:%s%s, env:%s)", |
| stanza_name, |
| token, |
| name ? " " : "", |
| name ? name : "", |
| element); |
| } else { |
| STACK_PUSH_NEW_ELEM (rpn_stack, element); |
| } |
| |
| } |
| } |
| |
| if (enumerate_events) |
| return; |
| |
| /* Handle case where a single event was specified (there |
| * was no operator to pop the entry off the stack). |
| */ |
| if (! STACK_EMPTY (rpn_stack)) { |
| if (! enumerate_events) { |
| /* Our job is done: show the user what we found. */ |
| nih_message (" %s %s", stanza_name, |
| STACK_PEEK (rpn_stack)); |
| } |
| } |
| } |
| |
| /** |
| * job_class_show_conditions: |
| * @job_class_proxy: D-Bus proxy for job class. |
| * @job_class_name: Name of config whose conditions we wish to display. |
| * |
| * Register D-Bus call-backs to display job classes start on and stop on |
| * conditions. |
| **/ |
| void |
| job_class_show_conditions (NihDBusProxy *job_class_proxy, const char *job_class_name) |
| { |
| DBusPendingCall *pending_call; |
| NihError *err; |
| ConditionHandlerData start_data, stop_data; |
| |
| nih_assert (job_class_proxy); |
| nih_assert (job_class_name); |
| |
| start_data.condition_name = "start on"; |
| start_data.job_class_name = job_class_name; |
| |
| stop_data.condition_name = "stop on"; |
| stop_data.job_class_name = job_class_name; |
| |
| pending_call = job_class_get_start_on (job_class_proxy, |
| job_class_condition_handler, |
| job_class_condition_err_handler, |
| &start_data, |
| NIH_DBUS_TIMEOUT_NEVER); |
| |
| if (!pending_call) |
| goto error; |
| |
| /* wait for completion */ |
| dbus_pending_call_block (pending_call); |
| dbus_pending_call_unref (pending_call); |
| |
| pending_call = job_class_get_stop_on (job_class_proxy, |
| job_class_condition_handler, |
| job_class_condition_err_handler, |
| &stop_data, |
| NIH_DBUS_TIMEOUT_NEVER); |
| |
| if (!pending_call) |
| goto error; |
| |
| /* wait for completion */ |
| dbus_pending_call_block (pending_call); |
| dbus_pending_call_unref (pending_call); |
| |
| return; |
| |
| error: |
| err = nih_error_get (); |
| nih_error ("%s", err->message); |
| nih_free (err); |
| } |
| |
| /** |
| * job_class_show_emits: |
| * @parent: parent object, |
| * @job_class_proxy: D-Bus proxy for job class, |
| * @job_class_name: Name of job class that emits an event. |
| * |
| * Display events job class emits to user. |
| **/ |
| void |
| job_class_show_emits (const void *parent, NihDBusProxy *job_class_proxy, const char *job_class_name) |
| { |
| NihError *err; |
| nih_local char **job_emits = NULL; |
| |
| nih_assert (job_class_proxy); |
| |
| if (job_class_get_emits_sync (parent, job_class_proxy, &job_emits) < 0) { |
| goto error; |
| } |
| |
| if (job_emits && *job_emits) { |
| char **p = job_emits; |
| while (*p) { |
| nih_message (" emits %s", *p); |
| p++; |
| } |
| } |
| |
| return; |
| |
| error: |
| err = nih_error_get (); |
| nih_error ("%s", err->message); |
| nih_free (err); |
| } |
| |
| /** |
| * job_class_condition_handler: |
| * @data: data passed via job_class_get_start_on() or job_class_get_stop_on(), |
| * @message: D-Bus message received, |
| * @value: array of variants generated by D-Bus call we are registering |
| * with. |
| * |
| * Handler for D-Bus message encoding a job classes "start on" or |
| * "stop on" condtions. |
| **/ |
| void |
| job_class_condition_handler (void *data, NihDBusMessage *message, char ** const *value) |
| { |
| job_class_parse_events ((const ConditionHandlerData *)data, value); |
| } |
| |
| /** |
| * job_class_condition_err_handler: |
| * |
| * @data data passed via job_class_get_start_on() or job_class_get_stop_on(), |
| * @message: D-Bus message received. |
| * |
| * Error handler for D-Bus message encoding a job classes "start on" or |
| * "stop on" conditions. |
| **/ |
| void |
| job_class_condition_err_handler (void *data, NihDBusMessage *message) |
| { |
| /* no remedial action possible */ |
| } |
| |
| #ifndef TEST |
| /** |
| * options: |
| * |
| * Command-line options accepted for all arguments. |
| **/ |
| static NihOption options[] = { |
| { 0, "session", N_("use D-Bus session bus to connect to init daemon (for testing)"), |
| NULL, NULL, NULL, dbus_bus_type_setter }, |
| { 0, "system", N_("use D-Bus system bus to connect to init daemon"), |
| NULL, NULL, NULL, dbus_bus_type_setter }, |
| { 0, "dest", N_("destination well-known name on D-Bus bus"), |
| NULL, "NAME", &dest_name, NULL }, |
| |
| NIH_OPTION_LAST |
| }; |
| |
| |
| /** |
| * start_options: |
| * |
| * Command-line options accepted for the start command. |
| **/ |
| NihOption start_options[] = { |
| { 'n', "no-wait", N_("do not wait for job to start before exiting"), |
| NULL, NULL, &no_wait, NULL }, |
| |
| NIH_OPTION_LAST |
| }; |
| |
| /** |
| * stop_options: |
| * |
| * Command-line options accepted for the stop command. |
| **/ |
| NihOption stop_options[] = { |
| { 'n', "no-wait", N_("do not wait for job to stop before exiting"), |
| NULL, NULL, &no_wait, NULL }, |
| |
| NIH_OPTION_LAST |
| }; |
| |
| /** |
| * restart_options: |
| * |
| * Command-line options accepted for the restart command. |
| **/ |
| NihOption restart_options[] = { |
| { 'n', "no-wait", N_("do not wait for job to restart before exiting"), |
| NULL, NULL, &no_wait, NULL }, |
| |
| NIH_OPTION_LAST |
| }; |
| |
| /** |
| * reload_options: |
| * |
| * Command-line options accepted for the reload command. |
| **/ |
| NihOption reload_options[] = { |
| NIH_OPTION_LAST |
| }; |
| |
| /** |
| * status_options: |
| * |
| * Command-line options accepted for the status command. |
| **/ |
| NihOption status_options[] = { |
| NIH_OPTION_LAST |
| }; |
| |
| /** |
| * list_options: |
| * |
| * Command-line options accepted for the list command. |
| **/ |
| NihOption list_options[] = { |
| NIH_OPTION_LAST |
| }; |
| |
| /** |
| * emit_options: |
| * |
| * Command-line options accepted for the emit command. |
| **/ |
| NihOption emit_options[] = { |
| { 'n', "no-wait", N_("do not wait for event to finish before exiting"), |
| NULL, NULL, &no_wait, NULL }, |
| |
| NIH_OPTION_LAST |
| }; |
| |
| /** |
| * reload_configuration_options: |
| * |
| * Command-line options accepted for the reload-configuration command. |
| **/ |
| NihOption reload_configuration_options[] = { |
| NIH_OPTION_LAST |
| }; |
| |
| /** |
| * version_options: |
| * |
| * Command-line options accepted for the version command. |
| **/ |
| NihOption version_options[] = { |
| NIH_OPTION_LAST |
| }; |
| |
| /** |
| * log_priority_options: |
| * |
| * Command-line options accepted for the log-priority command. |
| **/ |
| NihOption log_priority_options[] = { |
| NIH_OPTION_LAST |
| }; |
| |
| |
| /** |
| * show_config_options: |
| * |
| * Command-line options accepted for the show-config command. |
| **/ |
| NihOption show_config_options[] = { |
| { 'e', "enumerate", |
| N_("enumerate list of events and jobs causing job " |
| "created from job config to start/stop"), |
| NULL, NULL, &enumerate_events, NULL }, |
| |
| NIH_OPTION_LAST |
| }; |
| |
| /** |
| * job_group: |
| * |
| * Group of commands related to jobs. |
| **/ |
| static NihCommandGroup job_commands = { N_("Job") }; |
| |
| /** |
| * event_group: |
| * |
| * Group of commands related to events. |
| **/ |
| static NihCommandGroup event_commands = { N_("Event") }; |
| |
| /** |
| * commands: |
| * |
| * Commands accepts as the first non-option argument, or program name. |
| **/ |
| static NihCommand commands[] = { |
| { "start", N_("JOB [KEY=VALUE]..."), |
| N_("Start job."), |
| N_("JOB is the name of the job that is to be started, this may " |
| "be followed by zero or more environment variables to be " |
| "defined in the new job.\n" |
| "\n" |
| "The environment may also serve to distinguish between job " |
| "instances, and thus decide whether a new instance will be " |
| "started or an error returned if an existing instance is " |
| "already running."), |
| &job_commands, start_options, start_action }, |
| |
| { "stop", N_("JOB [KEY=VALUE]..."), |
| N_("Stop job."), |
| N_("JOB is the name of the job that is to be stopped, this may " |
| "be followed by zero or more environment variables to be " |
| "passed to the job's pre-stop and post-stop processes.\n" |
| "\n" |
| "The environment also serves to distinguish between job " |
| "instances, and thus decide which of multiple instances will " |
| "be stopped."), |
| &job_commands, stop_options, stop_action }, |
| |
| { "restart", N_("JOB [KEY=VALUE]..."), |
| N_("Restart job."), |
| N_("JOB is the name of the job that is to be restarted, this may " |
| "be followed by zero or more environment variables to be " |
| "defined in the job after restarting.\n" |
| "\n" |
| "The environment also serves to distinguish between job " |
| "instances, and thus decide which of multiple instances will " |
| "be restarted."), |
| &job_commands, restart_options, restart_action }, |
| |
| { "reload", N_("JOB [KEY=VALUE]..."), |
| N_("Send HUP signal to job."), |
| N_("JOB is the name of the job that is to be sent the signal, " |
| "this may be followed by zero or more environment variables " |
| "to distinguish between job instances.\n"), |
| &job_commands, reload_options, reload_action }, |
| |
| { "status", N_("JOB [KEY=VALUE]..."), |
| N_("Query status of job."), |
| N_("JOB is the name of the job that is to be queried, this may " |
| "be followed by zero or more environment variables to " |
| "distguish between job instances.\n" ), |
| &job_commands, status_options, status_action }, |
| |
| { "list", NULL, |
| N_("List known jobs."), |
| N_("The known jobs and their current status will be output."), |
| &job_commands, list_options, list_action }, |
| |
| { "emit", N_("EVENT [KEY=VALUE]..."), |
| N_("Emit an event."), |
| N_("EVENT is the name of an event the init daemon should emit, " |
| "this may be followed by zero or more environment variables " |
| "to be included in the event.\n"), |
| &event_commands, emit_options, emit_action }, |
| |
| { "reload-configuration", NULL, |
| N_("Reload the configuration of the init daemon."), |
| NULL, |
| NULL, reload_configuration_options, reload_configuration_action }, |
| { "version", NULL, |
| N_("Request the version of the init daemon."), |
| NULL, |
| NULL, version_options, version_action }, |
| { "log-priority", N_("[PRIORITY]"), |
| N_("Change the minimum priority of log messages from the init " |
| "daemon"), |
| N_("PRIORITY may be one of:\n" |
| " `debug' (messages useful for debugging upstart are logged, " |
| "equivalent to --debug on kernel command-line);\n" |
| " `info' (messages about job goal and state changes, as well " |
| "as event emissions are logged, equivalent to --verbose on the " |
| "kernel command-line);\n" |
| " `message' (informational and debugging messages are suppressed, " |
| "the default); " |
| " `warn' (ordinary messages are suppressed whilst still " |
| "logging warnings and errors);\n" |
| " `error' (only errors are logged, equivalent to --quiet on " |
| "the kernel command-line) or\n" |
| " `fatal' (only fatal errors are logged).\n" |
| "\n" |
| "Without arguments, this outputs the current log priority."), |
| NULL, log_priority_options, log_priority_action }, |
| |
| { "show-config", N_("[CONF]"), |
| N_("Show emits, start on and stop on details for job configurations."), |
| N_("If CONF specified, show configuration details for single job " |
| "configuration, else show details for all jobs configurations.\n"), |
| NULL, show_config_options, show_config_action }, |
| |
| NIH_COMMAND_LAST |
| }; |
| |
| |
| int |
| main (int argc, |
| char *argv[]) |
| { |
| int ret; |
| |
| nih_main_init (argv[0]); |
| |
| ret = nih_command_parser (NULL, argc, argv, options, commands); |
| if (ret < 0) |
| exit (1); |
| |
| dbus_shutdown (); |
| |
| return ret; |
| } |
| #endif |