blob: f02494bb2effd225a944e89041199a100cd6e252 [file] [log] [blame]
=== modified file 'dbus/com.ubuntu.Upstart.Job.xml'
--- dbus/com.ubuntu.Upstart.Job.xml 2009-07-03 16:28:21 +0000
+++ dbus/com.ubuntu.Upstart.Job.xml 2010-12-10 02:43:11 +0000
@@ -3,7 +3,7 @@
com.ubuntu.Upstart.Job.xml - interface definition for job objects
- Copyright © 2009 Canonical Ltd.
+ Copyright © 2010 Canonical Ltd.
Author: Scott James Remnant <scott@netsplit.com>.
This file is free software; Canonical Ltd gives unlimited permission
@@ -67,5 +67,10 @@
<property name="description" type="s" access="read" />
<property name="author" type="s" access="read" />
<property name="version" type="s" access="read" />
+
+ <!-- Information about a job's relationship with Events -->
+ <property name="start_on" type="aas" access="read" />
+ <property name="stop_on" type="aas" access="read" />
+ <property name="emits" type="as" access="read" />
</interface>
</node>
=== modified file 'init/job_class.c'
--- init/job_class.c 2010-12-13 18:15:24 +0000
+++ init/job_class.c 2010-12-14 15:30:06 +0000
@@ -2,7 +2,7 @@
*
* job_class.c - job class definition handling
*
- * Copyright © 2009 Canonical Ltd.
+ * Copyright © 2010 Canonical Ltd.
* Author: Scott James Remnant <scott@netsplit.com>.
*
* This program is free software; you can redistribute it and/or modify
@@ -32,6 +32,7 @@
#include <nih/string.h>
#include <nih/list.h>
#include <nih/hash.h>
+#include <nih/tree.h>
#include <nih/logging.h>
#include <nih-dbus/dbus_error.h>
@@ -1161,3 +1162,198 @@
return 0;
}
+
+
+/**
+ * job_class_get_start_on:
+ * @class: class to obtain events from,
+ * @message: D-Bus connection and message received,
+ * @start_on: pointer for reply array.
+ *
+ * Implements the get method for the start_on property of the
+ * com.ubuntu.Upstart.Job interface.
+ *
+ * Called to obtain the set of events that will start jobs of the given
+ * @class, this is returned as an array of the event tree flattened into
+ * reverse polish form.
+ *
+ * Each array element is an array of strings representing the events,
+ * or a single element containing "/OR" or "/AND" to represent the
+ * operators.
+ *
+ * Returns: zero on success, negative value on raised error.
+ **/
+int
+job_class_get_start_on (JobClass * class,
+ NihDBusMessage *message,
+ char **** start_on)
+{
+ size_t len = 0;
+
+ nih_assert (class != NULL);
+ nih_assert (message != NULL);
+ nih_assert (start_on != NULL);
+
+ *start_on = nih_alloc (message, sizeof (char ***));
+ if (! *start_on)
+ nih_return_no_memory_error (-1);
+
+ len = 0;
+ (*start_on)[len] = NULL;
+
+ if (class->start_on) {
+ NIH_TREE_FOREACH_POST (&class->start_on->node, iter) {
+ EventOperator *oper = (EventOperator *)iter;
+
+ *start_on = nih_realloc (*start_on, message,
+ sizeof (char ***) * (len + 2));
+ if (! *start_on)
+ nih_return_no_memory_error (-1);
+
+ (*start_on)[len] = nih_str_array_new (*start_on);
+ if (! (*start_on)[len])
+ nih_return_no_memory_error (-1);
+
+ switch (oper->type) {
+ case EVENT_OR:
+ if (! nih_str_array_add (&(*start_on)[len], *start_on,
+ NULL, "/OR"))
+ nih_return_no_memory_error (-1);
+ break;
+ case EVENT_AND:
+ if (! nih_str_array_add (&(*start_on)[len], *start_on,
+ NULL, "/AND"))
+ nih_return_no_memory_error (-1);
+ break;
+ case EVENT_MATCH:
+ if (! nih_str_array_add (&(*start_on)[len], *start_on,
+ NULL, oper->name))
+ nih_return_no_memory_error (-1);
+ if (oper->env)
+ if (! nih_str_array_append (&(*start_on)[len], *start_on,
+ NULL, oper->env))
+ nih_return_no_memory_error (-1);
+ break;
+ }
+
+ (*start_on)[++len] = NULL;
+ }
+ }
+
+ return 0;
+}
+
+/**
+ * job_class_get_stop_on:
+ * @class: class to obtain events from,
+ * @message: D-Bus connection and message received,
+ * @stop_on: pointer for reply array.
+ *
+ * Implements the get method for the stop_on property of the
+ * com.ubuntu.Upstart.Job interface.
+ *
+ * Called to obtain the set of events that will stop jobs of the given
+ * @class, this is returned as an array of the event tree flattened into
+ * reverse polish form.
+ *
+ * Each array element is an array of strings representing the events,
+ * or a single element containing "/OR" or "/AND" to represent the
+ * operators.
+ *
+ * Returns: zero on success, negative value on raised error.
+ **/
+int
+job_class_get_stop_on (JobClass * class,
+ NihDBusMessage *message,
+ char **** stop_on)
+{
+ size_t len = 0;
+
+ nih_assert (class != NULL);
+ nih_assert (message != NULL);
+ nih_assert (stop_on != NULL);
+
+ *stop_on = nih_alloc (message, sizeof (char ***));
+ if (! *stop_on)
+ nih_return_no_memory_error (-1);
+
+ len = 0;
+ (*stop_on)[len] = NULL;
+
+ if (class->stop_on) {
+ NIH_TREE_FOREACH_POST (&class->stop_on->node, iter) {
+ EventOperator *oper = (EventOperator *)iter;
+
+ *stop_on = nih_realloc (*stop_on, message,
+ sizeof (char ***) * (len + 2));
+ if (! *stop_on)
+ nih_return_no_memory_error (-1);
+
+ (*stop_on)[len] = nih_str_array_new (*stop_on);
+ if (! (*stop_on)[len])
+ nih_return_no_memory_error (-1);
+
+ switch (oper->type) {
+ case EVENT_OR:
+ if (! nih_str_array_add (&(*stop_on)[len], *stop_on,
+ NULL, "/OR"))
+ nih_return_no_memory_error (-1);
+ break;
+ case EVENT_AND:
+ if (! nih_str_array_add (&(*stop_on)[len], *stop_on,
+ NULL, "/AND"))
+ nih_return_no_memory_error (-1);
+ break;
+ case EVENT_MATCH:
+ if (! nih_str_array_add (&(*stop_on)[len], *stop_on,
+ NULL, oper->name))
+ nih_return_no_memory_error (-1);
+ if (oper->env)
+ if (! nih_str_array_append (&(*stop_on)[len], *stop_on,
+ NULL, oper->env))
+ nih_return_no_memory_error (-1);
+ break;
+ }
+
+ (*stop_on)[++len] = NULL;
+ }
+ }
+
+ return 0;
+}
+
+/**
+ * job_class_get_emits:
+ * @class: class to obtain events from,
+ * @message: D-Bus connection and message received,
+ * @emits: pointer for reply array.
+ *
+ * Implements the get method for the emits property of the
+ * com.ubuntu.Upstart.Job interface.
+ *
+ * Called to obtain the list of additional events of the given @class
+ * which will be stored as an array in @emits.
+ *
+ * Returns: zero on success, negative value on raised error.
+ **/
+int
+job_class_get_emits (JobClass * class,
+ NihDBusMessage *message,
+ char *** emits)
+{
+ nih_assert (class != NULL);
+ nih_assert (message != NULL);
+ nih_assert (emits != NULL);
+
+ if (class->emits) {
+ *emits = nih_str_array_copy (message, NULL, class->emits);
+ if (! *emits)
+ nih_return_no_memory_error (-1);
+ } else {
+ *emits = nih_str_array_new (message);
+ if (! *emits)
+ nih_return_no_memory_error (-1);
+ }
+
+ return 0;
+}
=== modified file 'init/job_class.h'
--- init/job_class.h 2010-12-13 18:15:24 +0000
+++ init/job_class.h 2010-12-14 15:30:06 +0000
@@ -1,6 +1,6 @@
/* upstart
*
- * Copyright © 2009 Canonical Ltd.
+ * Copyright © 2010 Canonical Ltd.
* Author: Scott James Remnant <scott@netsplit.com>.
*
* This program is free software; you can redistribute it and/or modify
@@ -220,6 +220,16 @@
char **version)
__attribute__ ((warn_unused_result));
+int job_class_get_start_on (JobClass *class,
+ NihDBusMessage *message,
+ char ****start_on);
+int job_class_get_stop_on (JobClass *class,
+ NihDBusMessage *message,
+ char ****stop_on);
+int job_class_get_emits (JobClass *class,
+ NihDBusMessage *message,
+ char ***emits);
+
NIH_END_EXTERN
#endif /* INIT_JOB_CLASS_H */
=== modified file 'init/tests/test_job_class.c'
--- init/tests/test_job_class.c 2009-07-09 11:50:19 +0000
+++ init/tests/test_job_class.c 2010-12-14 15:09:52 +0000
@@ -2,7 +2,7 @@
*
* test_job_class.c - test suite for init/job_class.c
*
- * Copyright © 2009 Canonical Ltd.
+ * Copyright © 2010 Canonical Ltd.
* Author: Scott James Remnant <scott@netsplit.com>.
*
* This program is free software; you can redistribute it and/or modify
@@ -3232,6 +3232,415 @@
}
}
+void
+test_get_start_on (void)
+{
+ NihDBusMessage *message = NULL;
+ JobClass *class = NULL;
+ EventOperator *oper = NULL;
+ EventOperator *and_oper = NULL;
+ NihError *error;
+ char ***start_on;
+ int ret;
+
+ TEST_FUNCTION ("job_class_get_start_on");
+
+ /* Check that the job's start_on tree is returned as a flattened
+ * array of string arrays, as a child of the message.
+ */
+ TEST_FEATURE ("with event tree");
+ nih_error_init ();
+ job_class_init ();
+
+ TEST_ALLOC_FAIL {
+ TEST_ALLOC_SAFE {
+ class = job_class_new (NULL, "test");
+
+ class->start_on = event_operator_new (
+ class, EVENT_OR, NULL, NULL);
+
+ and_oper = event_operator_new (
+ class, EVENT_AND, NULL, NULL);
+ nih_tree_add (&class->start_on->node, &and_oper->node,
+ NIH_TREE_LEFT);
+
+ oper = event_operator_new (
+ class->start_on, EVENT_MATCH, "foo", NULL);
+ oper->env = nih_str_array_new (oper);
+ NIH_MUST (nih_str_array_add (&oper->env, oper, NULL, "omnomnom"));
+ NIH_MUST (nih_str_array_add (&oper->env, oper, NULL, "ABER=crombie"));
+ NIH_MUST (nih_str_array_add (&oper->env, oper, NULL, "HOBBIT=frodo"));
+
+ nih_tree_add (&class->start_on->node, &oper->node,
+ NIH_TREE_RIGHT);
+
+ oper = event_operator_new (
+ class->start_on, EVENT_MATCH, "wibble", NULL);
+ nih_tree_add (&and_oper->node, &oper->node,
+ NIH_TREE_LEFT);
+
+ oper = event_operator_new (
+ class->start_on, EVENT_MATCH, "wobble", NULL);
+ nih_tree_add (&and_oper->node, &oper->node,
+ NIH_TREE_RIGHT);
+
+ message = nih_new (NULL, NihDBusMessage);
+ message->connection = NULL;
+ message->message = NULL;
+ }
+
+ start_on = NULL;
+
+ ret = job_class_get_start_on (class, message, &start_on);
+
+ if (test_alloc_failed) {
+ TEST_LT (ret, 0);
+
+ error = nih_error_get ();
+ TEST_EQ (error->number, ENOMEM);
+ nih_free (error);
+
+ nih_free (message);
+ nih_free (class);
+ continue;
+ }
+
+ TEST_EQ (ret, 0);
+
+ TEST_ALLOC_PARENT (start_on, message);
+ TEST_ALLOC_SIZE (start_on, sizeof (char **) * 6);
+
+ TEST_ALLOC_SIZE (start_on[0], sizeof (char *) * 2);
+ TEST_EQ_STR (start_on[0][0], "wibble");
+ TEST_EQ_P (start_on[0][1], NULL);
+
+ TEST_ALLOC_SIZE (start_on[1], sizeof (char *) * 2);
+ TEST_EQ_STR (start_on[1][0], "wobble");
+ TEST_EQ_P (start_on[1][1], NULL);
+
+ TEST_ALLOC_SIZE (start_on[2], sizeof (char *) * 2);
+ TEST_EQ_STR (start_on[2][0], "/AND");
+ TEST_EQ_P (start_on[2][1], NULL);
+
+ TEST_ALLOC_SIZE (start_on[3], sizeof (char *) * 5);
+ TEST_EQ_STR (start_on[3][0], "foo");
+ TEST_EQ_STR (start_on[3][1], "omnomnom");
+ TEST_EQ_STR (start_on[3][2], "ABER=crombie");
+ TEST_EQ_STR (start_on[3][3], "HOBBIT=frodo");
+ TEST_EQ_P (start_on[3][4], NULL);
+
+ TEST_ALLOC_SIZE (start_on[4], sizeof (char *) * 2);
+ TEST_EQ_STR (start_on[4][0], "/OR");
+ TEST_EQ_P (start_on[4][1], NULL);
+
+ TEST_EQ_P (start_on[5], NULL);
+
+ nih_free (message);
+ nih_free (class);
+ }
+
+
+ /* Check that an empty array is returned when the job has no
+ * start_on operator tree.
+ */
+ TEST_FEATURE ("with no events");
+ nih_error_init ();
+ job_class_init ();
+
+ TEST_ALLOC_FAIL {
+ TEST_ALLOC_SAFE {
+ class = job_class_new (NULL, "test");
+
+ message = nih_new (NULL, NihDBusMessage);
+ message->connection = NULL;
+ message->message = NULL;
+ }
+
+ start_on = NULL;
+
+ ret = job_class_get_start_on (class, message, &start_on);
+
+ if (test_alloc_failed) {
+ TEST_LT (ret, 0);
+
+ error = nih_error_get ();
+ TEST_EQ (error->number, ENOMEM);
+ nih_free (error);
+
+ nih_free (message);
+ nih_free (class);
+ continue;
+ }
+
+ TEST_EQ (ret, 0);
+
+ TEST_ALLOC_PARENT (start_on, message);
+ TEST_ALLOC_SIZE (start_on, sizeof (char **));
+ TEST_EQ_P (start_on[0], NULL);
+
+ nih_free (message);
+ nih_free (class);
+ }
+}
+
+void
+test_get_stop_on (void)
+{
+ NihDBusMessage *message = NULL;
+ JobClass *class = NULL;
+ EventOperator *oper = NULL;
+ EventOperator *and_oper = NULL;
+ NihError *error;
+ char ***stop_on;
+ int ret;
+
+ TEST_FUNCTION ("job_class_get_stop_on");
+
+ /* Check that the job's stop_on tree is returned as a flattened
+ * array of string arrays, as a child of the message.
+ */
+ TEST_FEATURE ("with event tree");
+ nih_error_init ();
+ job_class_init ();
+
+ TEST_ALLOC_FAIL {
+ TEST_ALLOC_SAFE {
+ class = job_class_new (NULL, "test");
+
+ class->stop_on = event_operator_new (
+ class, EVENT_OR, NULL, NULL);
+
+ and_oper = event_operator_new (
+ class, EVENT_AND, NULL, NULL);
+ nih_tree_add (&class->stop_on->node, &and_oper->node,
+ NIH_TREE_LEFT);
+
+ oper = event_operator_new (
+ class->stop_on, EVENT_MATCH, "foo", NULL);
+ oper->env = nih_str_array_new (oper);
+ NIH_MUST (nih_str_array_add (&oper->env, oper, NULL, "omnomnom"));
+ NIH_MUST (nih_str_array_add (&oper->env, oper, NULL, "ABER=crombie"));
+ NIH_MUST (nih_str_array_add (&oper->env, oper, NULL, "HOBBIT=frodo"));
+
+ nih_tree_add (&class->stop_on->node, &oper->node,
+ NIH_TREE_RIGHT);
+
+ oper = event_operator_new (
+ class->stop_on, EVENT_MATCH, "wibble", NULL);
+ nih_tree_add (&and_oper->node, &oper->node,
+ NIH_TREE_LEFT);
+
+ oper = event_operator_new (
+ class->stop_on, EVENT_MATCH, "wobble", NULL);
+ nih_tree_add (&and_oper->node, &oper->node,
+ NIH_TREE_RIGHT);
+
+ message = nih_new (NULL, NihDBusMessage);
+ message->connection = NULL;
+ message->message = NULL;
+ }
+
+ stop_on = NULL;
+
+ ret = job_class_get_stop_on (class, message, &stop_on);
+
+ if (test_alloc_failed) {
+ TEST_LT (ret, 0);
+
+ error = nih_error_get ();
+ TEST_EQ (error->number, ENOMEM);
+ nih_free (error);
+
+ nih_free (message);
+ nih_free (class);
+ continue;
+ }
+
+ TEST_EQ (ret, 0);
+
+ TEST_ALLOC_PARENT (stop_on, message);
+ TEST_ALLOC_SIZE (stop_on, sizeof (char **) * 6);
+
+ TEST_ALLOC_SIZE (stop_on[0], sizeof (char *) * 2);
+ TEST_EQ_STR (stop_on[0][0], "wibble");
+ TEST_EQ_P (stop_on[0][1], NULL);
+
+ TEST_ALLOC_SIZE (stop_on[1], sizeof (char *) * 2);
+ TEST_EQ_STR (stop_on[1][0], "wobble");
+ TEST_EQ_P (stop_on[1][1], NULL);
+
+ TEST_ALLOC_SIZE (stop_on[2], sizeof (char *) * 2);
+ TEST_EQ_STR (stop_on[2][0], "/AND");
+ TEST_EQ_P (stop_on[2][1], NULL);
+
+ TEST_ALLOC_SIZE (stop_on[3], sizeof (char *) * 5);
+ TEST_EQ_STR (stop_on[3][0], "foo");
+ TEST_EQ_STR (stop_on[3][1], "omnomnom");
+ TEST_EQ_STR (stop_on[3][2], "ABER=crombie");
+ TEST_EQ_STR (stop_on[3][3], "HOBBIT=frodo");
+ TEST_EQ_P (stop_on[3][4], NULL);
+
+ TEST_ALLOC_SIZE (stop_on[4], sizeof (char *) * 2);
+ TEST_EQ_STR (stop_on[4][0], "/OR");
+ TEST_EQ_P (stop_on[4][1], NULL);
+
+ TEST_EQ_P (stop_on[5], NULL);
+
+ nih_free (message);
+ nih_free (class);
+ }
+
+
+ /* Check that an empty array is returned when the job has no
+ * stop_on operator tree.
+ */
+ TEST_FEATURE ("with no events");
+ nih_error_init ();
+ job_class_init ();
+
+ TEST_ALLOC_FAIL {
+ TEST_ALLOC_SAFE {
+ class = job_class_new (NULL, "test");
+
+ message = nih_new (NULL, NihDBusMessage);
+ message->connection = NULL;
+ message->message = NULL;
+ }
+
+ stop_on = NULL;
+
+ ret = job_class_get_stop_on (class, message, &stop_on);
+
+ if (test_alloc_failed) {
+ TEST_LT (ret, 0);
+
+ error = nih_error_get ();
+ TEST_EQ (error->number, ENOMEM);
+ nih_free (error);
+
+ nih_free (message);
+ nih_free (class);
+ continue;
+ }
+
+ TEST_EQ (ret, 0);
+
+ TEST_ALLOC_PARENT (stop_on, message);
+ TEST_ALLOC_SIZE (stop_on, sizeof (char **));
+ TEST_EQ_P (stop_on[0], NULL);
+
+ nih_free (message);
+ nih_free (class);
+ }
+}
+
+void
+test_get_emits (void)
+{
+ NihDBusMessage *message = NULL;
+ JobClass *class = NULL;
+ NihError *error;
+ char **emits;
+ int ret;
+
+ TEST_FUNCTION ("job_class_get_emits");
+
+ /* Check that an array of strings is returned from the property
+ * as a child of the message when the job declares that it emits
+ * extra events.
+ */
+ TEST_FEATURE ("with events");
+ nih_error_init ();
+ job_class_init ();
+
+ TEST_ALLOC_FAIL {
+ TEST_ALLOC_SAFE {
+ class = job_class_new (NULL, "test");
+ class->emits = nih_str_array_new (class);
+
+ NIH_MUST (nih_str_array_add (&class->emits, class, NULL, "foo"));
+ NIH_MUST (nih_str_array_add (&class->emits, class, NULL, "bar"));
+ NIH_MUST (nih_str_array_add (&class->emits, class, NULL, "baz"));
+
+ message = nih_new (NULL, NihDBusMessage);
+ message->connection = NULL;
+ message->message = NULL;
+ }
+
+ emits = NULL;
+
+ ret = job_class_get_emits (class, message, &emits);
+
+ if (test_alloc_failed) {
+ TEST_LT (ret, 0);
+
+ error = nih_error_get ();
+ TEST_EQ (error->number, ENOMEM);
+ nih_free (error);
+
+ nih_free (message);
+ nih_free (class);
+ continue;
+ }
+
+ TEST_EQ (ret, 0);
+
+ TEST_ALLOC_PARENT (emits, message);
+ TEST_ALLOC_SIZE (emits, sizeof (char *) * 4);
+ TEST_EQ_STR (emits[0], "foo");
+ TEST_EQ_STR (emits[1], "bar");
+ TEST_EQ_STR (emits[2], "baz");
+ TEST_EQ_P (emits[3], NULL);
+
+ nih_free (message);
+ nih_free (class);
+ }
+
+
+ /* Check that an empty array is returned from the property
+ * as a child of the message when the job doesn't declare
+ * any particular emitted events.
+ */
+ TEST_FEATURE ("with no events");
+ nih_error_init ();
+ job_class_init ();
+
+ TEST_ALLOC_FAIL {
+ TEST_ALLOC_SAFE {
+ class = job_class_new (NULL, "test");
+
+ message = nih_new (NULL, NihDBusMessage);
+ message->connection = NULL;
+ message->message = NULL;
+ }
+
+ emits = NULL;
+
+ ret = job_class_get_emits (class, message, &emits);
+
+ if (test_alloc_failed) {
+ TEST_LT (ret, 0);
+
+ error = nih_error_get ();
+ TEST_EQ (error->number, ENOMEM);
+ nih_free (error);
+
+ nih_free (message);
+ nih_free (class);
+ continue;
+ }
+
+ TEST_EQ (ret, 0);
+
+ TEST_ALLOC_PARENT (emits, message);
+ TEST_ALLOC_SIZE (emits, sizeof (char *));
+ TEST_EQ_P (emits[0], NULL);
+
+ nih_free (message);
+ nih_free (class);
+ }
+}
+
int
main (int argc,
@@ -3256,6 +3665,9 @@
test_get_description ();
test_get_author ();
test_get_version ();
+ test_get_start_on ();
+ test_get_stop_on ();
+ test_get_emits ();
return 0;
}