Merge lp:~xnox/ubuntu/trusty/plymouth/private-upstart-socket into lp:ubuntu/trusty/plymouth

Proposed by Dimitri John Ledkov
Status: Merged
Merged at revision: 1480
Proposed branch: lp:~xnox/ubuntu/trusty/plymouth/private-upstart-socket
Merge into: lp:ubuntu/trusty/plymouth
Diff against target: 4818 lines (+4385/-150)
21 files modified
.pc/applied-patches (+4/-0)
.pc/dont-bail-on-dummy-terms.patch/src/upstart-bridge/plymouth-upstart-bridge.c (+339/-0)
.pc/no-print-empty-description.patch/src/upstart-bridge/ply-upstart-monitor.c (+1182/-0)
.pc/ubuntu-logo-scale-factor-2.patch/themes/ubuntu-logo/Makefile.am (+23/-0)
.pc/ubuntu-logo-scale-factor-2.patch/themes/ubuntu-logo/ubuntu-logo.plymouth.in (+8/-0)
.pc/use-upstart-private-socket.patch/src/upstart-bridge/ply-upstart-monitor.c (+1301/-0)
debian/changelog (+22/-0)
debian/control (+1/-1)
debian/patches/dont-bail-on-dummy-terms.patch (+17/-0)
debian/patches/no-print-empty-description.patch (+14/-0)
debian/patches/series (+4/-0)
debian/patches/ubuntu-logo-scale-factor-2.patch (+1202/-0)
debian/patches/use-upstart-private-socket.patch (+198/-0)
debian/plymouth-theme-ubuntu-logo.postinst (+6/-0)
debian/plymouth-theme-ubuntu-logo.prerm (+2/-0)
debian/plymouth.plymouth-upstart-bridge.upstart (+5/-2)
src/upstart-bridge/ply-upstart-monitor.c (+11/-130)
src/upstart-bridge/plymouth-upstart-bridge.c (+3/-1)
themes/ubuntu-logo/Makefile.am (+18/-5)
themes/ubuntu-logo/ubuntu-logo.plymouth.in (+2/-2)
themes/ubuntu-logo/ubuntu-logo.script.in (+23/-9)
To merge this branch: bzr merge lp:~xnox/ubuntu/trusty/plymouth/private-upstart-socket
Reviewer Review Type Date Requested Status
James Hunt Pending
Stéphane Graber Pending
Colin Watson Pending
Steve Langasek Pending
Ubuntu branches Pending
Review via email: mp+210672@code.launchpad.net

Commit message

* debian/patches/use-upstart-private-socket.patch: instead of using
  system dbus, use private upstart socket in the plymouth-upstart-bridge.
* debian/plymouth.plymouth-upstart-bridge.upstart: start
  plymouth-upstart-bridge on startup, and thus gather a more complete
  boot.log.
* debian/patches/dont-bail-on-dummy-terms.patch: don't bail
  plymouth-upstart-bridge if TERM is not set and/or running on a dummy
  terminal, as we can run on those. This makes console-log useful in
  lxc-containers and actually contain messages from upstart jobs
  starting and stopping.
* debian/patches/no-print-empty-description.patch: do not store
  description when dbus returns empty string, and thus stop printing
  empty "Starting... done" messages.
* debian/plymouth.plymouth-upstart-bridge.upstart: update stop on
  conditions to stop when plymouth-shutdown finishes.
* Make ubuntu-logo theme support scale factor, provide one plymouth
  theme with scale 1 and another with scale 2, until scale factor can be
  dynamically detected.
* Mark plymouth-upstart-bridge to respawn.

Description of the change

First this patch series fixes to use upstart private socket, and thus able to start on startup. That was mostly removing code to deal with system-bus, looking up nameowner, and monitoring nameowner changes.

Next I've tried testing plymouth-upstart-bridge in an lxc container, only to notice that it didn't work, thus i fixed running plymouth-upstart-bridge when $TERM is not set.

This resulted in loads of empty messages, but it was never intended to print empty messages, so i've fixed that (dbus returns empty string, not NULL).

And i've also removed description stanza from the startpar bridge (separate upload) such that one does not get extra messages about startpar bridge firing, for every upstart job that is printed.

One now gets a more complete /var/log/boot.log on more ubuntu configurations.

For HiDPI support, I've tweaked ubuntu-logo theme to support "scalingfactor" for all loaded images/text/layout, and generated one theme with scalingfactor set to 1 (same as current theme) and another one with scalingfactor set to 2 to support highdpi screens via update-alternatives, until we get scalingfactor detection and passing that to plymouth.

To post a comment you must log in.
1473. By Dimitri John Ledkov

system dbus, use private upstart socket in the plymouth-upstart-bridge.
* debian/patches/dont-bail-on-dummy-terms.patch: don't bail
plymouth-upstart-bridge if TERM is not set and/or running on a dummy
terminal, as we can run on those.

1474. By Dimitri John Ledkov

* debian/patches/no-print-empty-description.patch: do not store
description when dbus returns empty string, and thus stop printing
empty "Starting... done" messages.

1475. By Dimitri John Ledkov

debian/plymouth.plymouth-upstart-bridge.upstart: update stop on
conditions to stop when plymouth-shutdown finishes.

1476. By Dimitri John Ledkov

  empty "Starting... done" messages. LP: #1185560.

1477. By Dimitri John Ledkov

Make ubuntu-logo theme support scale factor, provide one plymouth
theme with scale 1 and another with scale 2, until scale factor can be
dynamically detected.

1478. By Dimitri John Ledkov

Mark plymouth-upstart-bridge to respawn.

1479. By Dimitri John Ledkov

Fix up scale-factor-2 patch

1480. By Dimitri John Ledkov

[ Dimitri John Ledkov ] LP: #1292458

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file '.pc/applied-patches'
2--- .pc/applied-patches 2013-12-02 04:53:37 +0000
3+++ .pc/applied-patches 2014-03-14 10:43:52 +0000
4@@ -13,3 +13,7 @@
5 Miscellaneous-fixes-for-compiler-warnings.patch
6 autoreconf.patch
7 details-update-status.patch
8+use-upstart-private-socket.patch
9+dont-bail-on-dummy-terms.patch
10+no-print-empty-description.patch
11+ubuntu-logo-scale-factor-2.patch
12
13=== added directory '.pc/dont-bail-on-dummy-terms.patch'
14=== added directory '.pc/dont-bail-on-dummy-terms.patch/src'
15=== added directory '.pc/dont-bail-on-dummy-terms.patch/src/upstart-bridge'
16=== added file '.pc/dont-bail-on-dummy-terms.patch/src/upstart-bridge/plymouth-upstart-bridge.c'
17--- .pc/dont-bail-on-dummy-terms.patch/src/upstart-bridge/plymouth-upstart-bridge.c 1970-01-01 00:00:00 +0000
18+++ .pc/dont-bail-on-dummy-terms.patch/src/upstart-bridge/plymouth-upstart-bridge.c 2014-03-14 10:43:52 +0000
19@@ -0,0 +1,339 @@
20+/* plymouth-upstart-bridge.c - bridge Upstart job state changes to Plymouth
21+ *
22+ * Copyright (C) 2010, 2011 Canonical Ltd.
23+ *
24+ * This program is free software; you can redistribute it and/or modify
25+ * it under the terms of the GNU General Public License as published by
26+ * the Free Software Foundation; either version 2, or (at your option)
27+ * any later version.
28+ *
29+ * This program is distributed in the hope that it will be useful,
30+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
31+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
32+ * GNU General Public License for more details.
33+ *
34+ * You should have received a copy of the GNU General Public License
35+ * along with this program; if not, write to the Free Software
36+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
37+ * 02111-1307, USA.
38+ *
39+ * Written by: Colin Watson <cjwatson@ubuntu.com>
40+ */
41+#include "config.h"
42+
43+#include <stdbool.h>
44+#include <signal.h>
45+#include <stdlib.h>
46+#include <stdio.h>
47+#include <string.h>
48+#include <unistd.h>
49+
50+#if defined(HAVE_NCURSESW_TERM_H)
51+#include <ncursesw/term.h>
52+#elif defined(HAVE_NCURSES_TERM_H)
53+#include <ncurses/term.h>
54+#else
55+#include <term.h>
56+#endif
57+
58+#include "ply-boot-client.h"
59+#include "ply-command-parser.h"
60+#include "ply-event-loop.h"
61+#include "ply-logger.h"
62+#include "ply-upstart-monitor.h"
63+
64+typedef struct
65+{
66+ ply_event_loop_t *loop;
67+ ply_boot_client_t *client;
68+ ply_upstart_monitor_t *upstart;
69+ ply_command_parser_t *command_parser;
70+} state_t;
71+
72+#ifndef TERMINAL_COLOR_RED
73+#define TERMINAL_COLOR_RED 1
74+#endif
75+
76+/* We don't care about the difference between "not a string capability" and
77+ * "cancelled or absent".
78+ */
79+static const char *
80+get_string_capability (const char *name)
81+{
82+ const char *value;
83+
84+ value = tigetstr ((char *) name);
85+ if (value == (const char *) -1)
86+ value = NULL;
87+
88+ return value;
89+}
90+
91+static bool
92+terminal_ignores_new_line_after_80_chars (void)
93+{
94+ return tigetflag ((char *) "xenl") != 0;
95+}
96+
97+static int
98+get_number_of_columns (void)
99+{
100+ int number_of_columns;
101+
102+ number_of_columns = tigetnum ((char *) "cols");
103+
104+ return number_of_columns;
105+}
106+
107+static bool
108+can_set_cursor_column (void)
109+{
110+ const char *capability;
111+
112+ capability = get_string_capability ("hpa");
113+
114+ return capability != NULL;
115+}
116+
117+static void
118+set_cursor_column (int column)
119+{
120+ const char *capability;
121+ const char *terminal_string;
122+
123+ capability = get_string_capability ("hpa");
124+ terminal_string = tiparm (capability, column);
125+ fputs (terminal_string, stdout);
126+}
127+
128+static bool
129+can_set_fg_color (void)
130+{
131+ const char *capability;
132+
133+ capability = get_string_capability ("setaf");
134+
135+ return capability != NULL;
136+}
137+
138+static void
139+set_fg_color (int color)
140+{
141+ const char *capability;
142+ const char *terminal_string;
143+
144+ capability = get_string_capability ("setaf");
145+ terminal_string = tiparm (capability, color);
146+ fputs (terminal_string, stdout);
147+}
148+
149+static void
150+unset_fg_color (void)
151+{
152+ const char *terminal_string;
153+
154+ terminal_string = get_string_capability ("op");
155+
156+ if (terminal_string == NULL)
157+ return;
158+
159+ fputs (terminal_string, stdout);
160+}
161+
162+static void
163+update_status (state_t *state,
164+ ply_upstart_monitor_job_properties_t *job,
165+ ply_upstart_monitor_instance_properties_t *instance,
166+ const char *action,
167+ bool is_okay)
168+{
169+ ply_boot_client_update_daemon (state->client, job->name, NULL, NULL, state);
170+
171+ if (job->description == NULL)
172+ return;
173+
174+ printf (" * %s%s%s",
175+ action ? action : "", action ? " " : "", job->description);
176+
177+ if (terminal_ignores_new_line_after_80_chars () && can_set_cursor_column ())
178+ {
179+ int number_of_columns, column;
180+
181+ number_of_columns = get_number_of_columns ();
182+
183+ if (number_of_columns < (int) strlen("[fail]"))
184+ number_of_columns = 80;
185+
186+ column = number_of_columns - strlen ("[fail]") - 1;
187+
188+ set_cursor_column (column);
189+
190+ if (is_okay)
191+ puts ("[ OK ]");
192+ else
193+ {
194+ bool supports_color;
195+
196+ supports_color = can_set_fg_color ();
197+
198+ fputs ("[", stdout);
199+
200+ if (supports_color)
201+ set_fg_color (TERMINAL_COLOR_RED);
202+
203+ fputs ("fail", stdout);
204+
205+ if (supports_color)
206+ unset_fg_color ();
207+
208+ puts ("]");
209+ }
210+ }
211+ else
212+ {
213+ if (is_okay)
214+ puts (" ...done.");
215+ else
216+ puts (" ...fail!");
217+ }
218+}
219+
220+static void
221+on_failed (void *data,
222+ ply_upstart_monitor_job_properties_t *job,
223+ ply_upstart_monitor_instance_properties_t *instance,
224+ int status)
225+{
226+ state_t *state = data;
227+
228+ if (job->is_task)
229+ update_status (state, job, instance, NULL, false);
230+ else
231+ {
232+ if (strcmp (instance->goal, "start") == 0)
233+ update_status (state, job, instance, "Starting", false);
234+ else if (strcmp (instance->goal, "stop") == 0)
235+ update_status (state, job, instance, "Stopping", false);
236+ }
237+}
238+
239+static void
240+on_state_changed (state_t *state,
241+ const char *old_state,
242+ ply_upstart_monitor_job_properties_t *job,
243+ ply_upstart_monitor_instance_properties_t *instance)
244+{
245+ if (instance->failed)
246+ return;
247+
248+ if (job->is_task)
249+ {
250+ if (strcmp (instance->state, "waiting") == 0)
251+ update_status (state, job, instance, NULL, true);
252+ }
253+ else
254+ {
255+ if (strcmp (instance->goal, "start") == 0)
256+ {
257+ if (strcmp (instance->state, "running") == 0)
258+ update_status (state, job, instance, "Starting", true);
259+ }
260+ else if (strcmp (instance->goal, "stop") == 0)
261+ {
262+ if (strcmp (instance->state, "waiting") == 0)
263+ update_status (state, job, instance, "Stopping", true);
264+ }
265+ }
266+}
267+
268+static void
269+on_disconnect (state_t *state)
270+{
271+ ply_trace ("disconnected from boot status daemon");
272+ ply_event_loop_exit (state->loop, 0);
273+}
274+
275+int
276+main (int argc,
277+ char **argv)
278+{
279+ state_t state = { 0 };
280+ bool should_help, should_be_verbose;
281+ bool is_connected;
282+ int exit_code;
283+
284+ exit_code = 0;
285+
286+ signal (SIGPIPE, SIG_IGN);
287+
288+ state.loop = ply_event_loop_new ();
289+ state.client = ply_boot_client_new ();
290+ state.command_parser = ply_command_parser_new ("plymouth-upstart-bridge", "Upstart job state bridge");
291+
292+ ply_command_parser_add_options (state.command_parser,
293+ "help", "This help message", PLY_COMMAND_OPTION_TYPE_FLAG,
294+ "debug", "Enable verbose debug logging", PLY_COMMAND_OPTION_TYPE_FLAG,
295+ NULL);
296+
297+ if (!ply_command_parser_parse_arguments (state.command_parser, state.loop, argv, argc))
298+ {
299+ char *help_string;
300+
301+ help_string = ply_command_parser_get_help_string (state.command_parser);
302+
303+ ply_error ("%s", help_string);
304+
305+ free (help_string);
306+ return 1;
307+ }
308+
309+ ply_command_parser_get_options (state.command_parser,
310+ "help", &should_help,
311+ "debug", &should_be_verbose,
312+ NULL);
313+
314+ if (should_help)
315+ {
316+ char *help_string;
317+
318+ help_string = ply_command_parser_get_help_string (state.command_parser);
319+
320+ puts (help_string);
321+
322+ free (help_string);
323+ return 0;
324+ }
325+
326+ if (should_be_verbose && !ply_is_tracing ())
327+ ply_toggle_tracing ();
328+
329+ setupterm (NULL, STDOUT_FILENO, NULL);
330+
331+ is_connected = ply_boot_client_connect (state.client,
332+ (ply_boot_client_disconnect_handler_t)
333+ on_disconnect, &state);
334+ if (!is_connected)
335+ {
336+ ply_trace ("daemon not running");
337+ return 1;
338+ }
339+
340+ ply_boot_client_attach_to_event_loop (state.client, state.loop);
341+ state.upstart = ply_upstart_monitor_new (state.loop);
342+ if (!state.upstart)
343+ return 1;
344+ ply_upstart_monitor_add_state_changed_handler (state.upstart,
345+ (ply_upstart_monitor_state_changed_handler_t)
346+ on_state_changed, &state);
347+ ply_upstart_monitor_add_failed_handler (state.upstart, on_failed, &state);
348+
349+ exit_code = ply_event_loop_run (state.loop);
350+
351+ ply_upstart_monitor_free (state.upstart);
352+ ply_boot_client_free (state.client);
353+
354+ ply_event_loop_free (state.loop);
355+
356+ return exit_code;
357+}
358+/* vim: set ts=4 sw=4 expandtab autoindent cindent cino={.5s,(0: */
359
360=== added directory '.pc/no-print-empty-description.patch'
361=== added directory '.pc/no-print-empty-description.patch/src'
362=== added directory '.pc/no-print-empty-description.patch/src/upstart-bridge'
363=== added file '.pc/no-print-empty-description.patch/src/upstart-bridge/ply-upstart-monitor.c'
364--- .pc/no-print-empty-description.patch/src/upstart-bridge/ply-upstart-monitor.c 1970-01-01 00:00:00 +0000
365+++ .pc/no-print-empty-description.patch/src/upstart-bridge/ply-upstart-monitor.c 2014-03-14 10:43:52 +0000
366@@ -0,0 +1,1182 @@
367+/* ply-upstart-monitor.c - Upstart D-Bus monitor
368+ *
369+ * Copyright (C) 2010, 2011 Canonical Ltd.
370+ *
371+ * This program is free software; you can redistribute it and/or modify
372+ * it under the terms of the GNU General Public License as published by
373+ * the Free Software Foundation; either version 2, or (at your option)
374+ * any later version.
375+ *
376+ * This program is distributed in the hope that it will be useful,
377+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
378+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
379+ * GNU General Public License for more details.
380+ *
381+ * You should have received a copy of the GNU General Public License
382+ * along with this program; if not, write to the Free Software
383+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
384+ * 02111-1307, USA.
385+ *
386+ * Written by: Colin Watson <cjwatson@ubuntu.com>
387+ */
388+#include "config.h"
389+#include "ply-upstart-monitor.h"
390+
391+#include <assert.h>
392+#include <stdbool.h>
393+#include <stdlib.h>
394+#include <stdio.h>
395+#include <string.h>
396+#include <sys/eventfd.h>
397+
398+#include <dbus/dbus.h>
399+
400+#include "ply-logger.h"
401+#include "ply-event-loop.h"
402+#include "ply-hashtable.h"
403+#include "ply-list.h"
404+#include "ply-utils.h"
405+
406+typedef struct
407+{
408+ ply_upstart_monitor_t *monitor;
409+ DBusTimeout *timeout;
410+} ply_upstart_monitor_timeout_t;
411+
412+struct _ply_upstart_monitor
413+{
414+ DBusConnection *connection;
415+ ply_event_loop_t *loop;
416+ ply_hashtable_t *jobs;
417+ ply_hashtable_t *all_instances;
418+ ply_upstart_monitor_state_changed_handler_t state_changed_handler;
419+ void *state_changed_data;
420+ ply_upstart_monitor_failed_handler_t failed_handler;
421+ void *failed_data;
422+ int dispatch_fd;
423+};
424+
425+typedef struct
426+{
427+ ply_upstart_monitor_t *monitor;
428+ ply_upstart_monitor_job_properties_t properties;
429+ ply_hashtable_t *instances;
430+ ply_list_t *pending_calls;
431+} ply_upstart_monitor_job_t;
432+
433+typedef struct
434+{
435+ ply_upstart_monitor_job_t *job;
436+ ply_upstart_monitor_instance_properties_t properties;
437+ ply_list_t *pending_calls;
438+ uint32_t state_changed : 1;
439+ uint32_t call_failed : 1;
440+} ply_upstart_monitor_instance_t;
441+
442+#define UPSTART_SERVICE NULL
443+#define DBUS_ADDRESS_UPSTART "unix:abstract=/com/ubuntu/upstart"
444+#define UPSTART_PATH "/com/ubuntu/Upstart"
445+#define UPSTART_INTERFACE_0_6 "com.ubuntu.Upstart0_6"
446+#define UPSTART_INTERFACE_0_6_JOB "com.ubuntu.Upstart0_6.Job"
447+#define UPSTART_INTERFACE_0_6_INSTANCE "com.ubuntu.Upstart0_6.Instance"
448+
449+/* Remove an entry from a hashtable, free the key, and return the data. */
450+static void *
451+hashtable_remove_and_free_key (ply_hashtable_t *hashtable,
452+ const void *key)
453+{
454+ void *reply_key, *reply_data;
455+
456+ if (!ply_hashtable_lookup_full (hashtable, (void *) key,
457+ &reply_key, &reply_data))
458+ return NULL;
459+ ply_hashtable_remove (hashtable, (void *) key);
460+ free (reply_key);
461+
462+ return reply_data;
463+}
464+
465+/* We assume, in general, that Upstart responds to D-Bus messages in a
466+ * single thread, and that it processes messages on a given connection in
467+ * the order in which they were sent. Taken together, these assumptions
468+ * imply a kind of coherence: a Properties.GetAll reply received after a
469+ * StateChanged signal must have been computed entirely after the state
470+ * change. Thus, if this function returns false (properties have not been
471+ * fetched yet), it should be safe to record an event as call until such
472+ * time as the properties of the instance are known.
473+ */
474+static bool
475+instance_is_initialized (ply_upstart_monitor_instance_t *instance)
476+{
477+ /* Note that the job may not have a description. */
478+ if (instance->job->properties.name &&
479+ instance->properties.name && instance->properties.goal &&
480+ instance->properties.state)
481+ return true;
482+ else
483+ return false;
484+}
485+
486+static void
487+on_get_all_instance_properties_finished (DBusPendingCall *call,
488+ ply_upstart_monitor_instance_t *instance)
489+{
490+ DBusMessage *reply;
491+ DBusMessageIter iter, array_iter, dict_iter, variant_iter;
492+ const char *key, *name, *goal, *state;
493+ ply_upstart_monitor_t *monitor;
494+
495+ assert (call != NULL);
496+ assert (instance != NULL);
497+
498+ reply = dbus_pending_call_steal_reply (call);
499+ if (reply == NULL)
500+ return;
501+ if (dbus_message_get_type (reply) != DBUS_MESSAGE_TYPE_METHOD_RETURN)
502+ goto out;
503+
504+ dbus_message_iter_init (reply, &iter);
505+ if (dbus_message_iter_get_arg_type (&iter) != DBUS_TYPE_ARRAY)
506+ goto out;
507+ dbus_message_iter_recurse (&iter, &array_iter);
508+
509+ while (dbus_message_iter_get_arg_type (&array_iter) == DBUS_TYPE_DICT_ENTRY)
510+ {
511+ dbus_message_iter_recurse (&array_iter, &dict_iter);
512+
513+ if (dbus_message_iter_get_arg_type (&dict_iter) != DBUS_TYPE_STRING)
514+ goto next_item;
515+
516+ dbus_message_iter_get_basic (&dict_iter, &key);
517+ if (key == NULL)
518+ goto next_item;
519+
520+ dbus_message_iter_next (&dict_iter);
521+ if (dbus_message_iter_get_arg_type (&dict_iter) != DBUS_TYPE_VARIANT)
522+ goto next_item;
523+ dbus_message_iter_recurse (&dict_iter, &variant_iter);
524+ if (dbus_message_iter_get_arg_type (&variant_iter) != DBUS_TYPE_STRING)
525+ goto next_item;
526+
527+ if (strcmp (key, "name") == 0)
528+ {
529+ dbus_message_iter_get_basic (&variant_iter, &name);
530+ if (name != NULL)
531+ {
532+ ply_trace ("%s: name = '%s'",
533+ instance->job->properties.name, name);
534+ instance->properties.name = strdup (name);
535+ }
536+ }
537+ else if (strcmp (key, "goal") == 0)
538+ {
539+ dbus_message_iter_get_basic (&variant_iter, &goal);
540+ if (goal != NULL)
541+ {
542+ ply_trace ("%s: goal = '%s'",
543+ instance->job->properties.name, goal);
544+ instance->properties.goal = strdup (goal);
545+ }
546+ }
547+ else if (strcmp (key, "state") == 0)
548+ {
549+ dbus_message_iter_get_basic (&variant_iter, &state);
550+ if (state != NULL)
551+ {
552+ ply_trace ("%s: state = '%s'",
553+ instance->job->properties.name, state);
554+ instance->properties.state = strdup (state);
555+ }
556+ }
557+
558+next_item:
559+ dbus_message_iter_next (&array_iter);
560+ }
561+
562+out:
563+ dbus_message_unref (reply);
564+
565+ if (instance_is_initialized (instance))
566+ {
567+ /* Process any call events. */
568+ monitor = instance->job->monitor;
569+
570+ if (instance->state_changed && monitor->state_changed_handler)
571+ monitor->state_changed_handler (monitor->state_changed_data, NULL,
572+ &instance->job->properties,
573+ &instance->properties);
574+ instance->state_changed = false;
575+
576+ if (instance->call_failed && monitor->failed_handler)
577+ monitor->failed_handler (monitor->failed_data,
578+ &instance->job->properties,
579+ &instance->properties,
580+ instance->properties.failed);
581+ instance->call_failed = false;
582+ }
583+}
584+
585+static void
586+on_get_all_job_properties_finished (DBusPendingCall *call,
587+ ply_upstart_monitor_job_t *job)
588+{
589+ DBusMessage *reply;
590+ DBusMessageIter iter, array_iter, dict_iter, variant_iter;
591+ const char *key, *name, *description;
592+ dbus_uint32_t task;
593+
594+ assert (call != NULL);
595+ assert (job != NULL);
596+
597+ reply = dbus_pending_call_steal_reply (call);
598+ if (reply == NULL)
599+ return;
600+ if (dbus_message_get_type (reply) != DBUS_MESSAGE_TYPE_METHOD_RETURN)
601+ goto out;
602+
603+ dbus_message_iter_init (reply, &iter);
604+ if (dbus_message_iter_get_arg_type (&iter) != DBUS_TYPE_ARRAY)
605+ goto out;
606+ dbus_message_iter_recurse (&iter, &array_iter);
607+
608+ while (dbus_message_iter_get_arg_type (&array_iter) == DBUS_TYPE_DICT_ENTRY)
609+ {
610+ dbus_message_iter_recurse (&array_iter, &dict_iter);
611+
612+ if (dbus_message_iter_get_arg_type (&dict_iter) != DBUS_TYPE_STRING)
613+ goto next_item;
614+
615+ dbus_message_iter_get_basic (&dict_iter, &key);
616+ if (key == NULL)
617+ goto next_item;
618+
619+ dbus_message_iter_next (&dict_iter);
620+ if (dbus_message_iter_get_arg_type (&dict_iter) != DBUS_TYPE_VARIANT)
621+ goto next_item;
622+ dbus_message_iter_recurse (&dict_iter, &variant_iter);
623+
624+ if (strcmp (key, "name") == 0)
625+ {
626+ if (dbus_message_iter_get_arg_type (&variant_iter) !=
627+ DBUS_TYPE_STRING)
628+ goto next_item;
629+ dbus_message_iter_get_basic (&variant_iter, &name);
630+ if (name != NULL)
631+ {
632+ ply_trace ("name = '%s'", name);
633+ job->properties.name = strdup (name);
634+ }
635+ }
636+ else if (strcmp (key, "description") == 0)
637+ {
638+ if (dbus_message_iter_get_arg_type (&variant_iter) !=
639+ DBUS_TYPE_STRING)
640+ goto next_item;
641+ dbus_message_iter_get_basic (&variant_iter, &description);
642+ if (description != NULL)
643+ {
644+ ply_trace ("description = '%s'", description);
645+ job->properties.description = strdup (description);
646+ }
647+ }
648+ else if (strcmp (key, "task") == 0)
649+ {
650+ if (dbus_message_iter_get_arg_type (&variant_iter) !=
651+ DBUS_TYPE_BOOLEAN)
652+ goto next_item;
653+ dbus_message_iter_get_basic (&variant_iter, &task);
654+ ply_trace ("task = %s", task ? "TRUE" : "FALSE");
655+ job->properties.is_task = task ? true : false;
656+ }
657+
658+next_item:
659+ dbus_message_iter_next (&array_iter);
660+ }
661+
662+out:
663+ dbus_message_unref (reply);
664+}
665+
666+static void
667+remove_instance_internal (ply_upstart_monitor_job_t *job, const char *path)
668+{
669+ ply_upstart_monitor_instance_t *instance;
670+ ply_list_node_t *node;
671+
672+ instance = hashtable_remove_and_free_key (job->instances, path);
673+ if (instance == NULL)
674+ return;
675+ hashtable_remove_and_free_key (job->monitor->all_instances, path);
676+
677+ node = ply_list_get_first_node (instance->pending_calls);
678+ while (node != NULL)
679+ {
680+ DBusPendingCall *call;
681+ ply_list_node_t *next_node;
682+
683+ call = ply_list_node_get_data (node);
684+ next_node = ply_list_get_next_node (instance->pending_calls, node);
685+ dbus_pending_call_cancel (call);
686+ dbus_pending_call_unref (call);
687+ node = next_node;
688+ }
689+ ply_list_free (instance->pending_calls);
690+
691+ free (instance->properties.name);
692+ free (instance->properties.goal);
693+ free (instance->properties.state);
694+ free (instance);
695+}
696+
697+static void
698+add_instance (ply_upstart_monitor_job_t *job,
699+ const char *path)
700+{
701+ ply_upstart_monitor_instance_t *instance;
702+ DBusMessage *message;
703+ const char *interface = UPSTART_INTERFACE_0_6_INSTANCE;
704+ DBusPendingCall *call;
705+
706+ ply_trace ("adding instance: %s", path);
707+
708+ remove_instance_internal (job, path);
709+
710+ instance = calloc (1, sizeof (ply_upstart_monitor_instance_t));
711+ instance->job = job;
712+ instance->properties.name = NULL;
713+ instance->properties.goal = NULL;
714+ instance->properties.state = NULL;
715+ instance->properties.failed = false;
716+ instance->pending_calls = ply_list_new ();
717+ instance->state_changed = false;
718+ instance->call_failed = false;
719+
720+ /* Keep a hash of instances per job, to make InstanceRemoved handling
721+ * easy.
722+ */
723+ ply_hashtable_insert (job->instances, strdup (path), instance);
724+ /* Keep a separate hash of all instances, to make StateChanged handling
725+ * easy.
726+ */
727+ ply_hashtable_insert (job->monitor->all_instances, strdup (path), instance);
728+
729+ /* Ask Upstart for the name, goal, and state properties. */
730+ ply_trace ("fetching properties of instance %s", path);
731+ message = dbus_message_new_method_call (UPSTART_SERVICE, path,
732+ DBUS_INTERFACE_PROPERTIES, "GetAll");
733+ dbus_message_append_args (message,
734+ DBUS_TYPE_STRING, &interface,
735+ DBUS_TYPE_INVALID);
736+ dbus_connection_send_with_reply (job->monitor->connection, message,
737+ &call, -1);
738+ dbus_message_unref (message);
739+ if (call != NULL)
740+ {
741+ dbus_pending_call_set_notify (call,
742+ (DBusPendingCallNotifyFunction)
743+ on_get_all_instance_properties_finished,
744+ instance, NULL);
745+ ply_list_append_data (instance->pending_calls, call);
746+ }
747+}
748+
749+static void
750+remove_instance (ply_upstart_monitor_job_t *job,
751+ const char *path)
752+{
753+ ply_trace ("removing instance: %s", path);
754+
755+ remove_instance_internal (job, path);
756+}
757+
758+static void
759+on_get_all_instances_finished (DBusPendingCall *call,
760+ ply_upstart_monitor_job_t *job)
761+{
762+ DBusMessage *reply;
763+ DBusError error;
764+ char **instances;
765+ int n_instances, i;
766+
767+ assert (call != NULL);
768+ assert (job != NULL);
769+
770+ reply = dbus_pending_call_steal_reply (call);
771+ if (reply == NULL)
772+ return;
773+ if (dbus_message_get_type (reply) != DBUS_MESSAGE_TYPE_METHOD_RETURN)
774+ goto out;
775+
776+ dbus_error_init (&error);
777+ dbus_message_get_args (reply, &error,
778+ DBUS_TYPE_ARRAY, DBUS_TYPE_OBJECT_PATH,
779+ &instances, &n_instances,
780+ DBUS_TYPE_INVALID);
781+ if (dbus_error_is_set (&error))
782+ goto out;
783+ dbus_error_free (&error);
784+
785+ for (i = 0; i < n_instances; ++i)
786+ add_instance (job, instances[i]);
787+
788+ dbus_free_string_array (instances);
789+
790+out:
791+ dbus_message_unref (reply);
792+}
793+
794+static void
795+free_job_instance (void *key, void *data, void *user_data)
796+{
797+ const char *path = key;
798+ ply_upstart_monitor_instance_t *instance = data;
799+ ply_upstart_monitor_t *monitor = user_data;
800+
801+ assert (monitor != NULL);
802+
803+ if (instance == NULL)
804+ return;
805+
806+ hashtable_remove_and_free_key (monitor->all_instances, path);
807+ free (instance->properties.name);
808+ free (instance->properties.goal);
809+ free (instance->properties.state);
810+ free (instance);
811+}
812+
813+static void
814+remove_job_internal (ply_upstart_monitor_t *monitor, const char *path)
815+{
816+ ply_upstart_monitor_job_t *job;
817+ ply_list_node_t *node;
818+
819+ job = hashtable_remove_and_free_key (monitor->jobs, path);
820+ if (job == NULL)
821+ return;
822+
823+ node = ply_list_get_first_node (job->pending_calls);
824+ while (node != NULL)
825+ {
826+ DBusPendingCall *call;
827+ ply_list_node_t *next_node;
828+
829+ call = ply_list_node_get_data (node);
830+ next_node = ply_list_get_next_node (job->pending_calls, node);
831+ dbus_pending_call_cancel (call);
832+ dbus_pending_call_unref (call);
833+ node = next_node;
834+ }
835+ ply_list_free (job->pending_calls);
836+
837+ free (job->properties.name);
838+ free (job->properties.description);
839+ ply_hashtable_foreach (job->instances, free_job_instance, monitor);
840+ ply_hashtable_free (job->instances);
841+ free (job);
842+}
843+
844+static void
845+add_job (ply_upstart_monitor_t *monitor, const char *path)
846+{
847+ ply_upstart_monitor_job_t *job;
848+ DBusMessage *message;
849+ const char *interface = UPSTART_INTERFACE_0_6_JOB;
850+ DBusPendingCall *call;
851+
852+ ply_trace ("adding job: %s", path);
853+
854+ remove_job_internal (monitor, path);
855+
856+ job = calloc (1, sizeof (ply_upstart_monitor_job_t));
857+ job->monitor = monitor;
858+ job->properties.name = NULL;
859+ job->properties.description = NULL;
860+ job->properties.is_task = false;
861+ job->instances = ply_hashtable_new (ply_hashtable_string_hash,
862+ ply_hashtable_string_compare);
863+ job->pending_calls = ply_list_new ();
864+
865+ ply_hashtable_insert (monitor->jobs, strdup (path), job);
866+
867+ /* Ask Upstart for the name and description properties. */
868+ ply_trace ("fetching properties of job %s", path);
869+ message = dbus_message_new_method_call (UPSTART_SERVICE, path,
870+ DBUS_INTERFACE_PROPERTIES, "GetAll");
871+ dbus_message_append_args (message,
872+ DBUS_TYPE_STRING, &interface,
873+ DBUS_TYPE_INVALID);
874+ dbus_connection_send_with_reply (monitor->connection, message, &call, -1);
875+ dbus_message_unref (message);
876+ if (call != NULL)
877+ {
878+ dbus_pending_call_set_notify (call,
879+ (DBusPendingCallNotifyFunction)
880+ on_get_all_job_properties_finished,
881+ job,
882+ NULL);
883+ ply_list_append_data (job->pending_calls, call);
884+ }
885+
886+ /* Ask Upstart for a list of all instances of this job. */
887+ ply_trace ("calling GetAllInstances on job %s", path);
888+ message = dbus_message_new_method_call (UPSTART_SERVICE, path,
889+ UPSTART_INTERFACE_0_6_JOB,
890+ "GetAllInstances");
891+ dbus_connection_send_with_reply (monitor->connection, message, &call, -1);
892+ dbus_message_unref (message);
893+ if (call != NULL)
894+ {
895+ dbus_pending_call_set_notify (call,
896+ (DBusPendingCallNotifyFunction)
897+ on_get_all_instances_finished,
898+ job,
899+ NULL);
900+ ply_list_append_data (job->pending_calls, call);
901+ }
902+}
903+
904+static void
905+remove_job (ply_upstart_monitor_t *monitor, const char *path)
906+{
907+ ply_trace ("removing job: %s", path);
908+
909+ remove_job_internal (monitor, path);
910+}
911+
912+static void
913+on_get_all_jobs_finished (DBusPendingCall *call,
914+ ply_upstart_monitor_t *monitor)
915+{
916+ DBusMessage *reply;
917+ DBusError error;
918+ char **jobs;
919+ int n_jobs, i;
920+
921+ assert (call != NULL);
922+ assert (monitor != NULL);
923+
924+ reply = dbus_pending_call_steal_reply (call);
925+ if (reply == NULL)
926+ return;
927+ if (dbus_message_get_type (reply) != DBUS_MESSAGE_TYPE_METHOD_RETURN)
928+ goto out;
929+
930+ dbus_error_init (&error);
931+ dbus_message_get_args (reply, &error,
932+ DBUS_TYPE_ARRAY, DBUS_TYPE_OBJECT_PATH,
933+ &jobs, &n_jobs,
934+ DBUS_TYPE_INVALID);
935+ if (dbus_error_is_set (&error))
936+ goto out;
937+ dbus_error_free (&error);
938+
939+ for (i = 0; i < n_jobs; ++i)
940+ add_job (monitor, jobs[i]);
941+
942+ dbus_free_string_array (jobs);
943+
944+out:
945+ dbus_message_unref (reply);
946+}
947+
948+
949+static DBusHandlerResult
950+job_added_handler (DBusConnection *connection,
951+ DBusMessage *message,
952+ ply_upstart_monitor_t *monitor)
953+{
954+ DBusError error;
955+ const char *signal_path;
956+
957+ ply_trace ("got JobAdded");
958+ dbus_error_init (&error);
959+ if (dbus_message_get_args (message, &error,
960+ DBUS_TYPE_OBJECT_PATH, &signal_path,
961+ DBUS_TYPE_INVALID))
962+ add_job (monitor, signal_path);
963+ dbus_error_free (&error);
964+ return DBUS_HANDLER_RESULT_HANDLED;
965+}
966+
967+static DBusHandlerResult
968+job_removed_handler (DBusConnection *connection,
969+ DBusMessage *message,
970+ ply_upstart_monitor_t *monitor)
971+{
972+ DBusError error;
973+ const char *signal_path;
974+
975+ ply_trace ("got JobRemoved");
976+ dbus_error_init (&error);
977+ if (dbus_message_get_args (message, &error,
978+ DBUS_TYPE_OBJECT_PATH, &signal_path,
979+ DBUS_TYPE_INVALID))
980+ remove_job (monitor, signal_path);
981+ dbus_error_free (&error);
982+ return DBUS_HANDLER_RESULT_HANDLED;
983+}
984+
985+static DBusHandlerResult
986+instance_added_handler (DBusConnection *connection, DBusMessage *message,
987+ ply_upstart_monitor_t *monitor, const char *path)
988+{
989+ DBusError error;
990+ const char *signal_path;
991+ ply_upstart_monitor_job_t *job;
992+
993+ ply_trace ("got %s InstanceAdded", path);
994+ job = ply_hashtable_lookup (monitor->jobs, (void *) path);
995+ if (job != NULL)
996+ {
997+ dbus_error_init (&error);
998+ if (dbus_message_get_args (message, &error,
999+ DBUS_TYPE_OBJECT_PATH, &signal_path,
1000+ DBUS_TYPE_INVALID))
1001+ add_instance (job, signal_path);
1002+ dbus_error_free (&error);
1003+ }
1004+ return DBUS_HANDLER_RESULT_HANDLED;
1005+}
1006+
1007+static DBusHandlerResult
1008+instance_removed_handler (DBusConnection *connection, DBusMessage *message,
1009+ ply_upstart_monitor_t *monitor, const char *path)
1010+{
1011+ DBusError error;
1012+ const char *signal_path;
1013+ ply_upstart_monitor_job_t *job;
1014+
1015+ ply_trace ("got %s InstanceRemoved", path);
1016+ job = ply_hashtable_lookup (monitor->jobs, (void *) path);
1017+ if (job != NULL)
1018+ {
1019+ dbus_error_init (&error);
1020+ if (dbus_message_get_args (message, &error,
1021+ DBUS_TYPE_OBJECT_PATH, &signal_path,
1022+ DBUS_TYPE_INVALID))
1023+ remove_instance (job, signal_path);
1024+ dbus_error_free (&error);
1025+ }
1026+ return DBUS_HANDLER_RESULT_HANDLED;
1027+}
1028+
1029+static DBusHandlerResult
1030+goal_changed_handler (DBusConnection *connection, DBusMessage *message,
1031+ ply_upstart_monitor_t *monitor, const char *path)
1032+{
1033+ DBusError error;
1034+ const char *goal;
1035+ ply_upstart_monitor_instance_t *instance;
1036+ char *old_goal;
1037+
1038+ ply_trace ("got %s GoalChanged", path);
1039+ instance = ply_hashtable_lookup (monitor->all_instances, (void *) path);
1040+ if (instance != NULL)
1041+ {
1042+ dbus_error_init (&error);
1043+ if (dbus_message_get_args (message, &error,
1044+ DBUS_TYPE_STRING, &goal,
1045+ DBUS_TYPE_INVALID))
1046+ {
1047+ old_goal = instance->properties.goal;
1048+ instance->properties.goal = strdup (goal);
1049+ ply_trace ("goal changed from '%s' to '%s'", old_goal, goal);
1050+ free (old_goal);
1051+ }
1052+ dbus_error_free (&error);
1053+ }
1054+ return DBUS_HANDLER_RESULT_HANDLED;
1055+}
1056+
1057+static DBusHandlerResult
1058+state_changed_handler (DBusConnection *connection, DBusMessage *message,
1059+ ply_upstart_monitor_t *monitor, const char *path)
1060+{
1061+ DBusError error;
1062+ const char *state;
1063+ ply_upstart_monitor_instance_t *instance;
1064+ char *old_state;
1065+
1066+ ply_trace ("got %s StateChanged", path);
1067+ instance = ply_hashtable_lookup (monitor->all_instances, (void *) path);
1068+ if (instance != NULL)
1069+ {
1070+ dbus_error_init (&error);
1071+ if (dbus_message_get_args (message, &error,
1072+ DBUS_TYPE_STRING, &state,
1073+ DBUS_TYPE_INVALID))
1074+ {
1075+ old_state = instance->properties.state;
1076+ instance->properties.state = strdup (state);
1077+ ply_trace ("state changed from '%s' to '%s'", old_state, state);
1078+ if (strcmp (state, "starting") == 0)
1079+ {
1080+ /* Clear any old failed information. */
1081+ instance->properties.failed = 0;
1082+ instance->call_failed = false;
1083+ }
1084+ if (instance_is_initialized (instance))
1085+ {
1086+ if (monitor->state_changed_handler)
1087+ monitor->state_changed_handler (monitor->state_changed_data,
1088+ old_state,
1089+ &instance->job->properties,
1090+ &instance->properties);
1091+ }
1092+ else
1093+ instance->state_changed = true;
1094+ free (old_state);
1095+ }
1096+ dbus_error_free (&error);
1097+ }
1098+ return DBUS_HANDLER_RESULT_HANDLED;
1099+}
1100+
1101+static DBusHandlerResult
1102+failed_handler (DBusConnection *connection, DBusMessage *message,
1103+ ply_upstart_monitor_t *monitor, const char *path)
1104+{
1105+ DBusError error;
1106+ ply_upstart_monitor_instance_t *instance;
1107+ dbus_int32_t failed_status;
1108+
1109+ ply_trace ("got %s Failed", path);
1110+ instance = ply_hashtable_lookup (monitor->all_instances, (void *) path);
1111+ if (instance != NULL)
1112+ {
1113+ dbus_error_init (&error);
1114+ if (dbus_message_get_args (message, &error,
1115+ DBUS_TYPE_INT32, &failed_status,
1116+ DBUS_TYPE_INVALID))
1117+ {
1118+ instance->properties.failed = failed_status;
1119+ if (instance_is_initialized (instance))
1120+ {
1121+ if (monitor->failed_handler)
1122+ monitor->failed_handler (monitor->failed_data,
1123+ &instance->job->properties,
1124+ &instance->properties,
1125+ (int) failed_status);
1126+ }
1127+ else
1128+ instance->call_failed = true;
1129+ }
1130+ dbus_error_free (&error);
1131+ }
1132+ return DBUS_HANDLER_RESULT_HANDLED;
1133+}
1134+
1135+static DBusHandlerResult
1136+message_handler (DBusConnection *connection, DBusMessage *message, void *data)
1137+{
1138+ ply_upstart_monitor_t *monitor = data;
1139+ const char *path;
1140+
1141+ assert (connection != NULL);
1142+ assert (message != NULL);
1143+ assert (monitor != NULL);
1144+
1145+ path = dbus_message_get_path (message);
1146+ if (path == NULL)
1147+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1148+
1149+ if (dbus_message_is_signal (message, UPSTART_INTERFACE_0_6,
1150+ "JobAdded"))
1151+ return job_added_handler (connection, message, monitor);
1152+
1153+ if (dbus_message_is_signal (message, UPSTART_INTERFACE_0_6,
1154+ "JobRemoved"))
1155+ return job_removed_handler (connection, message, monitor);
1156+
1157+ if (dbus_message_is_signal (message, UPSTART_INTERFACE_0_6_JOB,
1158+ "InstanceAdded"))
1159+ return instance_added_handler (connection, message, monitor, path);
1160+
1161+ if (dbus_message_is_signal (message, UPSTART_INTERFACE_0_6_JOB,
1162+ "InstanceRemoved"))
1163+ return instance_removed_handler (connection, message, monitor, path);
1164+
1165+ if (dbus_message_is_signal (message, UPSTART_INTERFACE_0_6_INSTANCE,
1166+ "GoalChanged"))
1167+ return goal_changed_handler (connection, message, monitor, path);
1168+
1169+ if (dbus_message_is_signal (message, UPSTART_INTERFACE_0_6_INSTANCE,
1170+ "StateChanged"))
1171+ return state_changed_handler (connection, message, monitor, path);
1172+
1173+ if (dbus_message_is_signal (message, UPSTART_INTERFACE_0_6_INSTANCE,
1174+ "Failed"))
1175+ return failed_handler (connection, message, monitor, path);
1176+
1177+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1178+}
1179+
1180+ply_upstart_monitor_t *
1181+ply_upstart_monitor_new (ply_event_loop_t *loop)
1182+{
1183+ DBusError error;
1184+ DBusConnection *connection;
1185+ ply_upstart_monitor_t *monitor;
1186+ DBusMessage *message;
1187+ DBusPendingCall *call;
1188+
1189+ dbus_error_init (&error);
1190+
1191+ /* Get a connection to the system bus and set it up to listen for messages
1192+ * from Upstart.
1193+ */
1194+ connection = dbus_connection_open (DBUS_ADDRESS_UPSTART, &error);
1195+ if (connection == NULL)
1196+ {
1197+ ply_error ("unable to connect to system bus: %s", error.message);
1198+ dbus_error_free (&error);
1199+ return NULL;
1200+ }
1201+ dbus_error_free (&error);
1202+
1203+ monitor = calloc (1, sizeof (ply_upstart_monitor_t));
1204+ monitor->connection = connection;
1205+ monitor->loop = NULL;
1206+ monitor->jobs = ply_hashtable_new (ply_hashtable_string_hash,
1207+ ply_hashtable_string_compare);
1208+ monitor->all_instances = ply_hashtable_new (ply_hashtable_string_hash,
1209+ ply_hashtable_string_compare);
1210+ monitor->state_changed_handler = NULL;
1211+ monitor->state_changed_data = NULL;
1212+ monitor->failed_handler = NULL;
1213+ monitor->failed_data = NULL;
1214+ monitor->dispatch_fd = -1;
1215+
1216+ if (!dbus_connection_add_filter (connection, message_handler, monitor, NULL))
1217+ {
1218+ ply_error ("unable to add filter to system bus connection");
1219+ ply_upstart_monitor_free (monitor);
1220+ return NULL;
1221+ }
1222+
1223+ ply_trace ("calling GetAllJobs");
1224+ message = dbus_message_new_method_call (UPSTART_SERVICE, UPSTART_PATH,
1225+ UPSTART_INTERFACE_0_6,
1226+ "GetAllJobs");
1227+ dbus_connection_send_with_reply (monitor->connection, message, &call, -1);
1228+ dbus_message_unref (message);
1229+ if (call != NULL)
1230+ dbus_pending_call_set_notify (call,
1231+ (DBusPendingCallNotifyFunction)
1232+ on_get_all_jobs_finished,
1233+ monitor, NULL);
1234+
1235+ if (loop != NULL)
1236+ ply_upstart_monitor_connect_to_event_loop (monitor, loop);
1237+
1238+ return monitor;
1239+}
1240+
1241+void
1242+ply_upstart_monitor_free (ply_upstart_monitor_t *monitor)
1243+{
1244+ if (monitor == NULL)
1245+ return;
1246+
1247+ ply_hashtable_free (monitor->all_instances);
1248+ ply_hashtable_free (monitor->jobs);
1249+ dbus_connection_unref (monitor->connection);
1250+ if (monitor->dispatch_fd >= 0)
1251+ close (monitor->dispatch_fd);
1252+ free (monitor);
1253+}
1254+
1255+static void
1256+read_watch_handler (void *data, int fd)
1257+{
1258+ DBusWatch *watch = data;
1259+
1260+ assert (watch != NULL);
1261+
1262+ dbus_watch_handle (watch, DBUS_WATCH_READABLE);
1263+}
1264+
1265+static void
1266+write_watch_handler (void *data, int fd)
1267+{
1268+ DBusWatch *watch = data;
1269+
1270+ assert (watch != NULL);
1271+
1272+ dbus_watch_handle (watch, DBUS_WATCH_WRITABLE);
1273+}
1274+
1275+static dbus_bool_t
1276+add_watch (DBusWatch *watch, void *data)
1277+{
1278+ ply_upstart_monitor_t *monitor = data;
1279+ unsigned int flags;
1280+ int fd;
1281+ ply_event_loop_fd_status_t status;
1282+ ply_fd_watch_t *read_watch_event = NULL, *write_watch_event = NULL;
1283+
1284+ assert (monitor != NULL);
1285+ assert (watch != NULL);
1286+
1287+ if (!dbus_watch_get_enabled (watch))
1288+ return TRUE;
1289+
1290+ assert (dbus_watch_get_data (watch) == NULL);
1291+
1292+ flags = dbus_watch_get_flags (watch);
1293+ fd = dbus_watch_get_unix_fd (watch);
1294+
1295+ if (flags & DBUS_WATCH_READABLE)
1296+ {
1297+ status = PLY_EVENT_LOOP_FD_STATUS_HAS_DATA;
1298+ read_watch_event = ply_event_loop_watch_fd (monitor->loop, fd, status,
1299+ read_watch_handler, NULL,
1300+ watch);
1301+ if (read_watch_event == NULL)
1302+ return FALSE;
1303+ dbus_watch_set_data (watch, read_watch_event, NULL);
1304+ }
1305+
1306+ if (flags & DBUS_WATCH_WRITABLE)
1307+ {
1308+ status = PLY_EVENT_LOOP_FD_STATUS_CAN_TAKE_DATA;
1309+ write_watch_event = ply_event_loop_watch_fd (monitor->loop, fd, status,
1310+ write_watch_handler, NULL,
1311+ watch);
1312+ if (write_watch_event == NULL)
1313+ {
1314+ if (read_watch_event != NULL)
1315+ ply_event_loop_stop_watching_fd (monitor->loop, read_watch_event);
1316+ return FALSE;
1317+ }
1318+ dbus_watch_set_data (watch, write_watch_event, NULL);
1319+ }
1320+
1321+ return TRUE;
1322+}
1323+
1324+static void
1325+remove_watch (DBusWatch *watch, void *data)
1326+{
1327+ ply_upstart_monitor_t *monitor = data;
1328+ ply_fd_watch_t *watch_event;
1329+
1330+ assert (monitor != NULL);
1331+ assert (watch != NULL);
1332+
1333+ watch_event = dbus_watch_get_data (watch);
1334+ if (watch_event == NULL)
1335+ return;
1336+
1337+ ply_event_loop_stop_watching_fd (monitor->loop, watch_event);
1338+
1339+ dbus_watch_set_data (watch, NULL, NULL);
1340+}
1341+
1342+static void
1343+toggled_watch (DBusWatch *watch, void *data)
1344+{
1345+ if (dbus_watch_get_enabled (watch))
1346+ add_watch (watch, data);
1347+ else
1348+ remove_watch (watch, data);
1349+}
1350+
1351+static ply_upstart_monitor_timeout_t *
1352+timeout_user_data_new (ply_upstart_monitor_t *monitor, DBusTimeout *timeout)
1353+{
1354+ ply_upstart_monitor_timeout_t *monitor_timeout;
1355+
1356+ monitor_timeout = calloc (1, sizeof (ply_upstart_monitor_timeout_t));
1357+ monitor_timeout->monitor = monitor;
1358+ monitor_timeout->timeout = timeout;
1359+
1360+ return monitor_timeout;
1361+}
1362+
1363+static void
1364+timeout_user_data_free (void *data)
1365+{
1366+ ply_upstart_monitor_timeout_t *monitor_timeout = data;
1367+
1368+ free (monitor_timeout);
1369+}
1370+
1371+static void
1372+timeout_handler (void *data, ply_event_loop_t *loop)
1373+{
1374+ ply_upstart_monitor_timeout_t *monitor_timeout = data;
1375+
1376+ assert (monitor_timeout != NULL);
1377+
1378+ dbus_timeout_handle (monitor_timeout->timeout);
1379+}
1380+
1381+static dbus_bool_t
1382+add_timeout (DBusTimeout *timeout, void *data)
1383+{
1384+ ply_upstart_monitor_t *monitor = data;
1385+ int interval;
1386+ ply_upstart_monitor_timeout_t *monitor_timeout;
1387+
1388+ assert (monitor != NULL);
1389+ assert (timeout != NULL);
1390+
1391+ if (!dbus_timeout_get_enabled (timeout))
1392+ return TRUE;
1393+
1394+ interval = dbus_timeout_get_interval (timeout) * 1000;
1395+
1396+ monitor_timeout = timeout_user_data_new (monitor, timeout);
1397+
1398+ ply_event_loop_watch_for_timeout (monitor->loop, (double) interval,
1399+ timeout_handler, monitor_timeout);
1400+
1401+ dbus_timeout_set_data (timeout, monitor_timeout, timeout_user_data_free);
1402+
1403+ return TRUE;
1404+}
1405+
1406+static void
1407+remove_timeout (DBusTimeout *timeout, void *data)
1408+{
1409+ ply_upstart_monitor_t *monitor = data;
1410+ ply_upstart_monitor_timeout_t *monitor_timeout;
1411+
1412+ assert (monitor != NULL);
1413+ assert (timeout != NULL);
1414+
1415+ monitor_timeout = dbus_timeout_get_data (timeout);
1416+ if (monitor_timeout == NULL)
1417+ return;
1418+
1419+ ply_event_loop_stop_watching_for_timeout (monitor->loop,
1420+ timeout_handler, monitor_timeout);
1421+
1422+ dbus_timeout_set_data (timeout, NULL, NULL);
1423+}
1424+
1425+static void
1426+toggled_timeout (DBusTimeout *timeout, void *data)
1427+{
1428+ if (dbus_timeout_get_enabled (timeout))
1429+ add_timeout (timeout, data);
1430+ else
1431+ remove_timeout (timeout, data);
1432+}
1433+
1434+static void
1435+dispatch_status (DBusConnection *connection, DBusDispatchStatus new_status,
1436+ void *data)
1437+{
1438+ ply_upstart_monitor_t *monitor = data;
1439+ uint64_t event_payload;
1440+
1441+ assert (monitor != NULL);
1442+
1443+ if (new_status != DBUS_DISPATCH_DATA_REMAINS)
1444+ return;
1445+
1446+ /* wake up event loop */
1447+ event_payload = 1;
1448+ ply_write (monitor->dispatch_fd, &event_payload, sizeof (event_payload));
1449+}
1450+
1451+static void
1452+dispatch (void *data, int fd)
1453+{
1454+ ply_upstart_monitor_t *monitor = data;
1455+ uint64_t event_payload;
1456+
1457+ assert (monitor != NULL);
1458+
1459+ /* reset eventfd to zero */
1460+ ply_read (fd, &event_payload, sizeof (event_payload));
1461+
1462+ while (dbus_connection_dispatch (monitor->connection) ==
1463+ DBUS_DISPATCH_DATA_REMAINS)
1464+ ;
1465+}
1466+
1467+bool
1468+ply_upstart_monitor_connect_to_event_loop (ply_upstart_monitor_t *monitor,
1469+ ply_event_loop_t *loop)
1470+{
1471+ ply_fd_watch_t *dispatch_event = NULL;
1472+ uint64_t event_payload;
1473+
1474+ assert (monitor != NULL);
1475+
1476+ monitor->loop = loop;
1477+ monitor->dispatch_fd = -1;
1478+
1479+ if (!dbus_connection_set_watch_functions (monitor->connection,
1480+ add_watch,
1481+ remove_watch,
1482+ toggled_watch,
1483+ monitor, NULL))
1484+ goto err;
1485+
1486+ if (!dbus_connection_set_timeout_functions (monitor->connection,
1487+ add_timeout,
1488+ remove_timeout,
1489+ toggled_timeout,
1490+ monitor, NULL))
1491+ goto err;
1492+
1493+ monitor->dispatch_fd = eventfd (0, EFD_CLOEXEC | EFD_NONBLOCK);
1494+ if (monitor->dispatch_fd < 0)
1495+ goto err;
1496+ /* make sure we wake up to dispatch the first time through */
1497+ event_payload = 1;
1498+ ply_write (monitor->dispatch_fd, &event_payload, sizeof (event_payload));
1499+
1500+ dispatch_event = ply_event_loop_watch_fd (monitor->loop,
1501+ monitor->dispatch_fd,
1502+ PLY_EVENT_LOOP_FD_STATUS_HAS_DATA,
1503+ dispatch, NULL, monitor);
1504+ if (dispatch_event == NULL)
1505+ goto err;
1506+
1507+ dbus_connection_set_dispatch_status_function (monitor->connection,
1508+ dispatch_status,
1509+ monitor, NULL);
1510+
1511+ return true;
1512+
1513+err:
1514+ dbus_connection_set_watch_functions (monitor->connection,
1515+ NULL, NULL, NULL, NULL, NULL);
1516+ dbus_connection_set_timeout_functions (monitor->connection,
1517+ NULL, NULL, NULL, NULL, NULL);
1518+ dbus_connection_set_dispatch_status_function (monitor->connection,
1519+ NULL, NULL, NULL);
1520+ if (dispatch_event != NULL)
1521+ ply_event_loop_stop_watching_fd (monitor->loop, dispatch_event);
1522+ if (monitor->dispatch_fd >= 0)
1523+ {
1524+ close (monitor->dispatch_fd);
1525+ monitor->dispatch_fd = -1;
1526+ }
1527+ monitor->loop = NULL;
1528+ return false;
1529+}
1530+
1531+void
1532+ply_upstart_monitor_add_state_changed_handler (ply_upstart_monitor_t *monitor,
1533+ ply_upstart_monitor_state_changed_handler_t handler,
1534+ void *user_data)
1535+{
1536+ monitor->state_changed_handler = handler;
1537+ monitor->state_changed_data = user_data;
1538+}
1539+
1540+void
1541+ply_upstart_monitor_add_failed_handler (ply_upstart_monitor_t *monitor,
1542+ ply_upstart_monitor_failed_handler_t handler,
1543+ void *user_data)
1544+{
1545+ monitor->failed_handler = handler;
1546+ monitor->failed_data = user_data;
1547+}
1548+/* vim: set ts=4 sw=4 expandtab autoindent cindent cino={.5s,(0: */
1549
1550=== added directory '.pc/ubuntu-logo-scale-factor-2.patch'
1551=== added directory '.pc/ubuntu-logo-scale-factor-2.patch/themes'
1552=== added directory '.pc/ubuntu-logo-scale-factor-2.patch/themes/ubuntu-logo'
1553=== added file '.pc/ubuntu-logo-scale-factor-2.patch/themes/ubuntu-logo/Makefile.am'
1554--- .pc/ubuntu-logo-scale-factor-2.patch/themes/ubuntu-logo/Makefile.am 1970-01-01 00:00:00 +0000
1555+++ .pc/ubuntu-logo-scale-factor-2.patch/themes/ubuntu-logo/Makefile.am 2014-03-14 10:43:52 +0000
1556@@ -0,0 +1,23 @@
1557+themedir = $(datadir)/plymouth/themes/ubuntu-logo
1558+nodist_theme_DATA = ubuntu-logo.plymouth
1559+dist_theme_DATA = ubuntu-logo.script \
1560+ ubuntu-logo.grub \
1561+ ubuntu_logo.png \
1562+ ubuntu_logo16.png \
1563+ password_field.png \
1564+ password_field16.png \
1565+ progress_dot_off.png \
1566+ progress_dot_off16.png \
1567+ progress_dot_on.png \
1568+ progress_dot_on16.png
1569+
1570+
1571+
1572+MAINTAINERCLEANFILES = Makefile.in ubuntu-logo.plymouth
1573+CLEANFILES = ubuntu-logo.plymouth
1574+
1575+ubuntu-logo.plymouth: $(srcdir)/ubuntu-logo.plymouth.in
1576+ sed -e 's,[@]PLYMOUTH_THEME_PATH[@],$(PLYMOUTH_THEME_PATH),g' \
1577+ $(srcdir)/ubuntu-logo.plymouth.in > ubuntu-logo.plymouth
1578+
1579+EXTRA_DIST = ubuntu-logo.plymouth.in
1580
1581=== added file '.pc/ubuntu-logo-scale-factor-2.patch/themes/ubuntu-logo/ubuntu-logo.plymouth.in'
1582--- .pc/ubuntu-logo-scale-factor-2.patch/themes/ubuntu-logo/ubuntu-logo.plymouth.in 1970-01-01 00:00:00 +0000
1583+++ .pc/ubuntu-logo-scale-factor-2.patch/themes/ubuntu-logo/ubuntu-logo.plymouth.in 2014-03-14 10:43:52 +0000
1584@@ -0,0 +1,8 @@
1585+[Plymouth Theme]
1586+Name=Ubuntu Logo
1587+Description=A theme that features a blank background with a logo.
1588+ModuleName=script
1589+
1590+[script]
1591+ImageDir=@PLYMOUTH_THEME_PATH@/ubuntu-logo
1592+ScriptFile=@PLYMOUTH_THEME_PATH@/ubuntu-logo/ubuntu-logo.script
1593
1594=== added file '.pc/ubuntu-logo-scale-factor-2.patch/themes/ubuntu-logo/ubuntu-logo.script.in'
1595=== added directory '.pc/use-upstart-private-socket.patch'
1596=== added directory '.pc/use-upstart-private-socket.patch/src'
1597=== added directory '.pc/use-upstart-private-socket.patch/src/upstart-bridge'
1598=== added file '.pc/use-upstart-private-socket.patch/src/upstart-bridge/ply-upstart-monitor.c'
1599--- .pc/use-upstart-private-socket.patch/src/upstart-bridge/ply-upstart-monitor.c 1970-01-01 00:00:00 +0000
1600+++ .pc/use-upstart-private-socket.patch/src/upstart-bridge/ply-upstart-monitor.c 2014-03-14 10:43:52 +0000
1601@@ -0,0 +1,1301 @@
1602+/* ply-upstart-monitor.c - Upstart D-Bus monitor
1603+ *
1604+ * Copyright (C) 2010, 2011 Canonical Ltd.
1605+ *
1606+ * This program is free software; you can redistribute it and/or modify
1607+ * it under the terms of the GNU General Public License as published by
1608+ * the Free Software Foundation; either version 2, or (at your option)
1609+ * any later version.
1610+ *
1611+ * This program is distributed in the hope that it will be useful,
1612+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1613+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1614+ * GNU General Public License for more details.
1615+ *
1616+ * You should have received a copy of the GNU General Public License
1617+ * along with this program; if not, write to the Free Software
1618+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
1619+ * 02111-1307, USA.
1620+ *
1621+ * Written by: Colin Watson <cjwatson@ubuntu.com>
1622+ */
1623+#include "config.h"
1624+#include "ply-upstart-monitor.h"
1625+
1626+#include <assert.h>
1627+#include <stdbool.h>
1628+#include <stdlib.h>
1629+#include <stdio.h>
1630+#include <string.h>
1631+#include <sys/eventfd.h>
1632+
1633+#include <dbus/dbus.h>
1634+
1635+#include "ply-logger.h"
1636+#include "ply-event-loop.h"
1637+#include "ply-hashtable.h"
1638+#include "ply-list.h"
1639+#include "ply-utils.h"
1640+
1641+typedef struct
1642+{
1643+ ply_upstart_monitor_t *monitor;
1644+ DBusTimeout *timeout;
1645+} ply_upstart_monitor_timeout_t;
1646+
1647+struct _ply_upstart_monitor
1648+{
1649+ DBusConnection *connection;
1650+ char *owner;
1651+ ply_event_loop_t *loop;
1652+ ply_hashtable_t *jobs;
1653+ ply_hashtable_t *all_instances;
1654+ ply_upstart_monitor_state_changed_handler_t state_changed_handler;
1655+ void *state_changed_data;
1656+ ply_upstart_monitor_failed_handler_t failed_handler;
1657+ void *failed_data;
1658+ int dispatch_fd;
1659+};
1660+
1661+typedef struct
1662+{
1663+ ply_upstart_monitor_t *monitor;
1664+ ply_upstart_monitor_job_properties_t properties;
1665+ ply_hashtable_t *instances;
1666+ ply_list_t *pending_calls;
1667+} ply_upstart_monitor_job_t;
1668+
1669+typedef struct
1670+{
1671+ ply_upstart_monitor_job_t *job;
1672+ ply_upstart_monitor_instance_properties_t properties;
1673+ ply_list_t *pending_calls;
1674+ uint32_t state_changed : 1;
1675+ uint32_t call_failed : 1;
1676+} ply_upstart_monitor_instance_t;
1677+
1678+#define UPSTART_SERVICE "com.ubuntu.Upstart"
1679+#define UPSTART_PATH "/com/ubuntu/Upstart"
1680+#define UPSTART_INTERFACE_0_6 "com.ubuntu.Upstart0_6"
1681+#define UPSTART_INTERFACE_0_6_JOB "com.ubuntu.Upstart0_6.Job"
1682+#define UPSTART_INTERFACE_0_6_INSTANCE "com.ubuntu.Upstart0_6.Instance"
1683+
1684+/* Remove an entry from a hashtable, free the key, and return the data. */
1685+static void *
1686+hashtable_remove_and_free_key (ply_hashtable_t *hashtable,
1687+ const void *key)
1688+{
1689+ void *reply_key, *reply_data;
1690+
1691+ if (!ply_hashtable_lookup_full (hashtable, (void *) key,
1692+ &reply_key, &reply_data))
1693+ return NULL;
1694+ ply_hashtable_remove (hashtable, (void *) key);
1695+ free (reply_key);
1696+
1697+ return reply_data;
1698+}
1699+
1700+/* We assume, in general, that Upstart responds to D-Bus messages in a
1701+ * single thread, and that it processes messages on a given connection in
1702+ * the order in which they were sent. Taken together, these assumptions
1703+ * imply a kind of coherence: a Properties.GetAll reply received after a
1704+ * StateChanged signal must have been computed entirely after the state
1705+ * change. Thus, if this function returns false (properties have not been
1706+ * fetched yet), it should be safe to record an event as call until such
1707+ * time as the properties of the instance are known.
1708+ */
1709+static bool
1710+instance_is_initialized (ply_upstart_monitor_instance_t *instance)
1711+{
1712+ /* Note that the job may not have a description. */
1713+ if (instance->job->properties.name &&
1714+ instance->properties.name && instance->properties.goal &&
1715+ instance->properties.state)
1716+ return true;
1717+ else
1718+ return false;
1719+}
1720+
1721+static void
1722+on_get_all_instance_properties_finished (DBusPendingCall *call,
1723+ ply_upstart_monitor_instance_t *instance)
1724+{
1725+ DBusMessage *reply;
1726+ DBusMessageIter iter, array_iter, dict_iter, variant_iter;
1727+ const char *key, *name, *goal, *state;
1728+ ply_upstart_monitor_t *monitor;
1729+
1730+ assert (call != NULL);
1731+ assert (instance != NULL);
1732+
1733+ reply = dbus_pending_call_steal_reply (call);
1734+ if (reply == NULL)
1735+ return;
1736+ if (dbus_message_get_type (reply) != DBUS_MESSAGE_TYPE_METHOD_RETURN)
1737+ goto out;
1738+
1739+ dbus_message_iter_init (reply, &iter);
1740+ if (dbus_message_iter_get_arg_type (&iter) != DBUS_TYPE_ARRAY)
1741+ goto out;
1742+ dbus_message_iter_recurse (&iter, &array_iter);
1743+
1744+ while (dbus_message_iter_get_arg_type (&array_iter) == DBUS_TYPE_DICT_ENTRY)
1745+ {
1746+ dbus_message_iter_recurse (&array_iter, &dict_iter);
1747+
1748+ if (dbus_message_iter_get_arg_type (&dict_iter) != DBUS_TYPE_STRING)
1749+ goto next_item;
1750+
1751+ dbus_message_iter_get_basic (&dict_iter, &key);
1752+ if (key == NULL)
1753+ goto next_item;
1754+
1755+ dbus_message_iter_next (&dict_iter);
1756+ if (dbus_message_iter_get_arg_type (&dict_iter) != DBUS_TYPE_VARIANT)
1757+ goto next_item;
1758+ dbus_message_iter_recurse (&dict_iter, &variant_iter);
1759+ if (dbus_message_iter_get_arg_type (&variant_iter) != DBUS_TYPE_STRING)
1760+ goto next_item;
1761+
1762+ if (strcmp (key, "name") == 0)
1763+ {
1764+ dbus_message_iter_get_basic (&variant_iter, &name);
1765+ if (name != NULL)
1766+ {
1767+ ply_trace ("%s: name = '%s'",
1768+ instance->job->properties.name, name);
1769+ instance->properties.name = strdup (name);
1770+ }
1771+ }
1772+ else if (strcmp (key, "goal") == 0)
1773+ {
1774+ dbus_message_iter_get_basic (&variant_iter, &goal);
1775+ if (goal != NULL)
1776+ {
1777+ ply_trace ("%s: goal = '%s'",
1778+ instance->job->properties.name, goal);
1779+ instance->properties.goal = strdup (goal);
1780+ }
1781+ }
1782+ else if (strcmp (key, "state") == 0)
1783+ {
1784+ dbus_message_iter_get_basic (&variant_iter, &state);
1785+ if (state != NULL)
1786+ {
1787+ ply_trace ("%s: state = '%s'",
1788+ instance->job->properties.name, state);
1789+ instance->properties.state = strdup (state);
1790+ }
1791+ }
1792+
1793+next_item:
1794+ dbus_message_iter_next (&array_iter);
1795+ }
1796+
1797+out:
1798+ dbus_message_unref (reply);
1799+
1800+ if (instance_is_initialized (instance))
1801+ {
1802+ /* Process any call events. */
1803+ monitor = instance->job->monitor;
1804+
1805+ if (instance->state_changed && monitor->state_changed_handler)
1806+ monitor->state_changed_handler (monitor->state_changed_data, NULL,
1807+ &instance->job->properties,
1808+ &instance->properties);
1809+ instance->state_changed = false;
1810+
1811+ if (instance->call_failed && monitor->failed_handler)
1812+ monitor->failed_handler (monitor->failed_data,
1813+ &instance->job->properties,
1814+ &instance->properties,
1815+ instance->properties.failed);
1816+ instance->call_failed = false;
1817+ }
1818+}
1819+
1820+static void
1821+on_get_all_job_properties_finished (DBusPendingCall *call,
1822+ ply_upstart_monitor_job_t *job)
1823+{
1824+ DBusMessage *reply;
1825+ DBusMessageIter iter, array_iter, dict_iter, variant_iter;
1826+ const char *key, *name, *description;
1827+ dbus_uint32_t task;
1828+
1829+ assert (call != NULL);
1830+ assert (job != NULL);
1831+
1832+ reply = dbus_pending_call_steal_reply (call);
1833+ if (reply == NULL)
1834+ return;
1835+ if (dbus_message_get_type (reply) != DBUS_MESSAGE_TYPE_METHOD_RETURN)
1836+ goto out;
1837+
1838+ dbus_message_iter_init (reply, &iter);
1839+ if (dbus_message_iter_get_arg_type (&iter) != DBUS_TYPE_ARRAY)
1840+ goto out;
1841+ dbus_message_iter_recurse (&iter, &array_iter);
1842+
1843+ while (dbus_message_iter_get_arg_type (&array_iter) == DBUS_TYPE_DICT_ENTRY)
1844+ {
1845+ dbus_message_iter_recurse (&array_iter, &dict_iter);
1846+
1847+ if (dbus_message_iter_get_arg_type (&dict_iter) != DBUS_TYPE_STRING)
1848+ goto next_item;
1849+
1850+ dbus_message_iter_get_basic (&dict_iter, &key);
1851+ if (key == NULL)
1852+ goto next_item;
1853+
1854+ dbus_message_iter_next (&dict_iter);
1855+ if (dbus_message_iter_get_arg_type (&dict_iter) != DBUS_TYPE_VARIANT)
1856+ goto next_item;
1857+ dbus_message_iter_recurse (&dict_iter, &variant_iter);
1858+
1859+ if (strcmp (key, "name") == 0)
1860+ {
1861+ if (dbus_message_iter_get_arg_type (&variant_iter) !=
1862+ DBUS_TYPE_STRING)
1863+ goto next_item;
1864+ dbus_message_iter_get_basic (&variant_iter, &name);
1865+ if (name != NULL)
1866+ {
1867+ ply_trace ("name = '%s'", name);
1868+ job->properties.name = strdup (name);
1869+ }
1870+ }
1871+ else if (strcmp (key, "description") == 0)
1872+ {
1873+ if (dbus_message_iter_get_arg_type (&variant_iter) !=
1874+ DBUS_TYPE_STRING)
1875+ goto next_item;
1876+ dbus_message_iter_get_basic (&variant_iter, &description);
1877+ if (description != NULL)
1878+ {
1879+ ply_trace ("description = '%s'", description);
1880+ job->properties.description = strdup (description);
1881+ }
1882+ }
1883+ else if (strcmp (key, "task") == 0)
1884+ {
1885+ if (dbus_message_iter_get_arg_type (&variant_iter) !=
1886+ DBUS_TYPE_BOOLEAN)
1887+ goto next_item;
1888+ dbus_message_iter_get_basic (&variant_iter, &task);
1889+ ply_trace ("task = %s", task ? "TRUE" : "FALSE");
1890+ job->properties.is_task = task ? true : false;
1891+ }
1892+
1893+next_item:
1894+ dbus_message_iter_next (&array_iter);
1895+ }
1896+
1897+out:
1898+ dbus_message_unref (reply);
1899+}
1900+
1901+static void
1902+remove_instance_internal (ply_upstart_monitor_job_t *job, const char *path)
1903+{
1904+ ply_upstart_monitor_instance_t *instance;
1905+ ply_list_node_t *node;
1906+
1907+ instance = hashtable_remove_and_free_key (job->instances, path);
1908+ if (instance == NULL)
1909+ return;
1910+ hashtable_remove_and_free_key (job->monitor->all_instances, path);
1911+
1912+ node = ply_list_get_first_node (instance->pending_calls);
1913+ while (node != NULL)
1914+ {
1915+ DBusPendingCall *call;
1916+ ply_list_node_t *next_node;
1917+
1918+ call = ply_list_node_get_data (node);
1919+ next_node = ply_list_get_next_node (instance->pending_calls, node);
1920+ dbus_pending_call_cancel (call);
1921+ dbus_pending_call_unref (call);
1922+ node = next_node;
1923+ }
1924+ ply_list_free (instance->pending_calls);
1925+
1926+ free (instance->properties.name);
1927+ free (instance->properties.goal);
1928+ free (instance->properties.state);
1929+ free (instance);
1930+}
1931+
1932+static void
1933+add_instance (ply_upstart_monitor_job_t *job,
1934+ const char *path)
1935+{
1936+ ply_upstart_monitor_instance_t *instance;
1937+ DBusMessage *message;
1938+ const char *interface = UPSTART_INTERFACE_0_6_INSTANCE;
1939+ DBusPendingCall *call;
1940+
1941+ ply_trace ("adding instance: %s", path);
1942+
1943+ remove_instance_internal (job, path);
1944+
1945+ instance = calloc (1, sizeof (ply_upstart_monitor_instance_t));
1946+ instance->job = job;
1947+ instance->properties.name = NULL;
1948+ instance->properties.goal = NULL;
1949+ instance->properties.state = NULL;
1950+ instance->properties.failed = false;
1951+ instance->pending_calls = ply_list_new ();
1952+ instance->state_changed = false;
1953+ instance->call_failed = false;
1954+
1955+ /* Keep a hash of instances per job, to make InstanceRemoved handling
1956+ * easy.
1957+ */
1958+ ply_hashtable_insert (job->instances, strdup (path), instance);
1959+ /* Keep a separate hash of all instances, to make StateChanged handling
1960+ * easy.
1961+ */
1962+ ply_hashtable_insert (job->monitor->all_instances, strdup (path), instance);
1963+
1964+ /* Ask Upstart for the name, goal, and state properties. */
1965+ ply_trace ("fetching properties of instance %s", path);
1966+ message = dbus_message_new_method_call (UPSTART_SERVICE, path,
1967+ DBUS_INTERFACE_PROPERTIES, "GetAll");
1968+ dbus_message_append_args (message,
1969+ DBUS_TYPE_STRING, &interface,
1970+ DBUS_TYPE_INVALID);
1971+ dbus_connection_send_with_reply (job->monitor->connection, message,
1972+ &call, -1);
1973+ dbus_message_unref (message);
1974+ if (call != NULL)
1975+ {
1976+ dbus_pending_call_set_notify (call,
1977+ (DBusPendingCallNotifyFunction)
1978+ on_get_all_instance_properties_finished,
1979+ instance, NULL);
1980+ ply_list_append_data (instance->pending_calls, call);
1981+ }
1982+}
1983+
1984+static void
1985+remove_instance (ply_upstart_monitor_job_t *job,
1986+ const char *path)
1987+{
1988+ ply_trace ("removing instance: %s", path);
1989+
1990+ remove_instance_internal (job, path);
1991+}
1992+
1993+static void
1994+on_get_all_instances_finished (DBusPendingCall *call,
1995+ ply_upstart_monitor_job_t *job)
1996+{
1997+ DBusMessage *reply;
1998+ DBusError error;
1999+ char **instances;
2000+ int n_instances, i;
2001+
2002+ assert (call != NULL);
2003+ assert (job != NULL);
2004+
2005+ reply = dbus_pending_call_steal_reply (call);
2006+ if (reply == NULL)
2007+ return;
2008+ if (dbus_message_get_type (reply) != DBUS_MESSAGE_TYPE_METHOD_RETURN)
2009+ goto out;
2010+
2011+ dbus_error_init (&error);
2012+ dbus_message_get_args (reply, &error,
2013+ DBUS_TYPE_ARRAY, DBUS_TYPE_OBJECT_PATH,
2014+ &instances, &n_instances,
2015+ DBUS_TYPE_INVALID);
2016+ if (dbus_error_is_set (&error))
2017+ goto out;
2018+ dbus_error_free (&error);
2019+
2020+ for (i = 0; i < n_instances; ++i)
2021+ add_instance (job, instances[i]);
2022+
2023+ dbus_free_string_array (instances);
2024+
2025+out:
2026+ dbus_message_unref (reply);
2027+}
2028+
2029+static void
2030+free_job_instance (void *key, void *data, void *user_data)
2031+{
2032+ const char *path = key;
2033+ ply_upstart_monitor_instance_t *instance = data;
2034+ ply_upstart_monitor_t *monitor = user_data;
2035+
2036+ assert (monitor != NULL);
2037+
2038+ if (instance == NULL)
2039+ return;
2040+
2041+ hashtable_remove_and_free_key (monitor->all_instances, path);
2042+ free (instance->properties.name);
2043+ free (instance->properties.goal);
2044+ free (instance->properties.state);
2045+ free (instance);
2046+}
2047+
2048+static void
2049+remove_job_internal (ply_upstart_monitor_t *monitor, const char *path)
2050+{
2051+ ply_upstart_monitor_job_t *job;
2052+ ply_list_node_t *node;
2053+
2054+ job = hashtable_remove_and_free_key (monitor->jobs, path);
2055+ if (job == NULL)
2056+ return;
2057+
2058+ node = ply_list_get_first_node (job->pending_calls);
2059+ while (node != NULL)
2060+ {
2061+ DBusPendingCall *call;
2062+ ply_list_node_t *next_node;
2063+
2064+ call = ply_list_node_get_data (node);
2065+ next_node = ply_list_get_next_node (job->pending_calls, node);
2066+ dbus_pending_call_cancel (call);
2067+ dbus_pending_call_unref (call);
2068+ node = next_node;
2069+ }
2070+ ply_list_free (job->pending_calls);
2071+
2072+ free (job->properties.name);
2073+ free (job->properties.description);
2074+ ply_hashtable_foreach (job->instances, free_job_instance, monitor);
2075+ ply_hashtable_free (job->instances);
2076+ free (job);
2077+}
2078+
2079+static void
2080+add_job (ply_upstart_monitor_t *monitor, const char *path)
2081+{
2082+ ply_upstart_monitor_job_t *job;
2083+ DBusMessage *message;
2084+ const char *interface = UPSTART_INTERFACE_0_6_JOB;
2085+ DBusPendingCall *call;
2086+
2087+ ply_trace ("adding job: %s", path);
2088+
2089+ remove_job_internal (monitor, path);
2090+
2091+ job = calloc (1, sizeof (ply_upstart_monitor_job_t));
2092+ job->monitor = monitor;
2093+ job->properties.name = NULL;
2094+ job->properties.description = NULL;
2095+ job->properties.is_task = false;
2096+ job->instances = ply_hashtable_new (ply_hashtable_string_hash,
2097+ ply_hashtable_string_compare);
2098+ job->pending_calls = ply_list_new ();
2099+
2100+ ply_hashtable_insert (monitor->jobs, strdup (path), job);
2101+
2102+ /* Ask Upstart for the name and description properties. */
2103+ ply_trace ("fetching properties of job %s", path);
2104+ message = dbus_message_new_method_call (UPSTART_SERVICE, path,
2105+ DBUS_INTERFACE_PROPERTIES, "GetAll");
2106+ dbus_message_append_args (message,
2107+ DBUS_TYPE_STRING, &interface,
2108+ DBUS_TYPE_INVALID);
2109+ dbus_connection_send_with_reply (monitor->connection, message, &call, -1);
2110+ dbus_message_unref (message);
2111+ if (call != NULL)
2112+ {
2113+ dbus_pending_call_set_notify (call,
2114+ (DBusPendingCallNotifyFunction)
2115+ on_get_all_job_properties_finished,
2116+ job,
2117+ NULL);
2118+ ply_list_append_data (job->pending_calls, call);
2119+ }
2120+
2121+ /* Ask Upstart for a list of all instances of this job. */
2122+ ply_trace ("calling GetAllInstances on job %s", path);
2123+ message = dbus_message_new_method_call (UPSTART_SERVICE, path,
2124+ UPSTART_INTERFACE_0_6_JOB,
2125+ "GetAllInstances");
2126+ dbus_connection_send_with_reply (monitor->connection, message, &call, -1);
2127+ dbus_message_unref (message);
2128+ if (call != NULL)
2129+ {
2130+ dbus_pending_call_set_notify (call,
2131+ (DBusPendingCallNotifyFunction)
2132+ on_get_all_instances_finished,
2133+ job,
2134+ NULL);
2135+ ply_list_append_data (job->pending_calls, call);
2136+ }
2137+}
2138+
2139+static void
2140+remove_job (ply_upstart_monitor_t *monitor, const char *path)
2141+{
2142+ ply_trace ("removing job: %s", path);
2143+
2144+ remove_job_internal (monitor, path);
2145+}
2146+
2147+static void
2148+on_get_all_jobs_finished (DBusPendingCall *call,
2149+ ply_upstart_monitor_t *monitor)
2150+{
2151+ DBusMessage *reply;
2152+ DBusError error;
2153+ char **jobs;
2154+ int n_jobs, i;
2155+
2156+ assert (call != NULL);
2157+ assert (monitor != NULL);
2158+
2159+ reply = dbus_pending_call_steal_reply (call);
2160+ if (reply == NULL)
2161+ return;
2162+ if (dbus_message_get_type (reply) != DBUS_MESSAGE_TYPE_METHOD_RETURN)
2163+ goto out;
2164+
2165+ dbus_error_init (&error);
2166+ dbus_message_get_args (reply, &error,
2167+ DBUS_TYPE_ARRAY, DBUS_TYPE_OBJECT_PATH,
2168+ &jobs, &n_jobs,
2169+ DBUS_TYPE_INVALID);
2170+ if (dbus_error_is_set (&error))
2171+ goto out;
2172+ dbus_error_free (&error);
2173+
2174+ for (i = 0; i < n_jobs; ++i)
2175+ add_job (monitor, jobs[i]);
2176+
2177+ dbus_free_string_array (jobs);
2178+
2179+out:
2180+ dbus_message_unref (reply);
2181+}
2182+
2183+static void
2184+on_get_name_owner_finished (DBusPendingCall *call,
2185+ ply_upstart_monitor_t *monitor)
2186+{
2187+ DBusMessage *reply, *message;
2188+ DBusError error;
2189+ const char *owner;
2190+
2191+ assert (call != NULL);
2192+ assert (monitor != NULL);
2193+
2194+ reply = dbus_pending_call_steal_reply (call);
2195+ if (reply == NULL)
2196+ return;
2197+ if (dbus_message_get_type (reply) != DBUS_MESSAGE_TYPE_METHOD_RETURN)
2198+ goto out;
2199+
2200+ dbus_error_init (&error);
2201+ dbus_message_get_args (reply, &error,
2202+ DBUS_TYPE_STRING, &owner,
2203+ DBUS_TYPE_INVALID);
2204+ if (dbus_error_is_set (&error))
2205+ goto out;
2206+ dbus_error_free (&error);
2207+
2208+ ply_trace ("owner = '%s'", owner);
2209+
2210+ free (monitor->owner);
2211+ monitor->owner = strdup (owner);
2212+
2213+ ply_trace ("calling GetAllJobs");
2214+ message = dbus_message_new_method_call (UPSTART_SERVICE, UPSTART_PATH,
2215+ UPSTART_INTERFACE_0_6,
2216+ "GetAllJobs");
2217+ dbus_connection_send_with_reply (monitor->connection, message, &call, -1);
2218+ dbus_message_unref (message);
2219+ if (call != NULL)
2220+ dbus_pending_call_set_notify (call,
2221+ (DBusPendingCallNotifyFunction)
2222+ on_get_all_jobs_finished,
2223+ monitor, NULL);
2224+
2225+out:
2226+ dbus_message_unref (reply);
2227+}
2228+
2229+static DBusHandlerResult
2230+name_owner_changed_handler (DBusConnection *connection,
2231+ DBusMessage *message,
2232+ ply_upstart_monitor_t *monitor)
2233+{
2234+ DBusError error;
2235+ const char *name, *old_owner, *new_owner;
2236+
2237+ assert (connection != NULL);
2238+ assert (message != NULL);
2239+ assert (monitor != NULL);
2240+
2241+ dbus_error_init (&error);
2242+ if (dbus_message_get_args (message, &error,
2243+ DBUS_TYPE_STRING, &name,
2244+ DBUS_TYPE_STRING, &old_owner,
2245+ DBUS_TYPE_STRING, &new_owner,
2246+ DBUS_TYPE_INVALID) &&
2247+ strcmp (name, UPSTART_SERVICE) == 0)
2248+ {
2249+ if (new_owner)
2250+ ply_trace ("owner changed from '%s' to '%s'", old_owner, new_owner);
2251+ else
2252+ ply_trace ("owner left bus");
2253+ free (monitor->owner);
2254+ monitor->owner = new_owner ? strdup (new_owner) : NULL;
2255+ }
2256+
2257+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; /* let other handlers try */
2258+}
2259+
2260+static DBusHandlerResult
2261+job_added_handler (DBusConnection *connection,
2262+ DBusMessage *message,
2263+ ply_upstart_monitor_t *monitor)
2264+{
2265+ DBusError error;
2266+ const char *signal_path;
2267+
2268+ ply_trace ("got JobAdded");
2269+ dbus_error_init (&error);
2270+ if (dbus_message_get_args (message, &error,
2271+ DBUS_TYPE_OBJECT_PATH, &signal_path,
2272+ DBUS_TYPE_INVALID))
2273+ add_job (monitor, signal_path);
2274+ dbus_error_free (&error);
2275+ return DBUS_HANDLER_RESULT_HANDLED;
2276+}
2277+
2278+static DBusHandlerResult
2279+job_removed_handler (DBusConnection *connection,
2280+ DBusMessage *message,
2281+ ply_upstart_monitor_t *monitor)
2282+{
2283+ DBusError error;
2284+ const char *signal_path;
2285+
2286+ ply_trace ("got JobRemoved");
2287+ dbus_error_init (&error);
2288+ if (dbus_message_get_args (message, &error,
2289+ DBUS_TYPE_OBJECT_PATH, &signal_path,
2290+ DBUS_TYPE_INVALID))
2291+ remove_job (monitor, signal_path);
2292+ dbus_error_free (&error);
2293+ return DBUS_HANDLER_RESULT_HANDLED;
2294+}
2295+
2296+static DBusHandlerResult
2297+instance_added_handler (DBusConnection *connection, DBusMessage *message,
2298+ ply_upstart_monitor_t *monitor, const char *path)
2299+{
2300+ DBusError error;
2301+ const char *signal_path;
2302+ ply_upstart_monitor_job_t *job;
2303+
2304+ ply_trace ("got %s InstanceAdded", path);
2305+ job = ply_hashtable_lookup (monitor->jobs, (void *) path);
2306+ if (job != NULL)
2307+ {
2308+ dbus_error_init (&error);
2309+ if (dbus_message_get_args (message, &error,
2310+ DBUS_TYPE_OBJECT_PATH, &signal_path,
2311+ DBUS_TYPE_INVALID))
2312+ add_instance (job, signal_path);
2313+ dbus_error_free (&error);
2314+ }
2315+ return DBUS_HANDLER_RESULT_HANDLED;
2316+}
2317+
2318+static DBusHandlerResult
2319+instance_removed_handler (DBusConnection *connection, DBusMessage *message,
2320+ ply_upstart_monitor_t *monitor, const char *path)
2321+{
2322+ DBusError error;
2323+ const char *signal_path;
2324+ ply_upstart_monitor_job_t *job;
2325+
2326+ ply_trace ("got %s InstanceRemoved", path);
2327+ job = ply_hashtable_lookup (monitor->jobs, (void *) path);
2328+ if (job != NULL)
2329+ {
2330+ dbus_error_init (&error);
2331+ if (dbus_message_get_args (message, &error,
2332+ DBUS_TYPE_OBJECT_PATH, &signal_path,
2333+ DBUS_TYPE_INVALID))
2334+ remove_instance (job, signal_path);
2335+ dbus_error_free (&error);
2336+ }
2337+ return DBUS_HANDLER_RESULT_HANDLED;
2338+}
2339+
2340+static DBusHandlerResult
2341+goal_changed_handler (DBusConnection *connection, DBusMessage *message,
2342+ ply_upstart_monitor_t *monitor, const char *path)
2343+{
2344+ DBusError error;
2345+ const char *goal;
2346+ ply_upstart_monitor_instance_t *instance;
2347+ char *old_goal;
2348+
2349+ ply_trace ("got %s GoalChanged", path);
2350+ instance = ply_hashtable_lookup (monitor->all_instances, (void *) path);
2351+ if (instance != NULL)
2352+ {
2353+ dbus_error_init (&error);
2354+ if (dbus_message_get_args (message, &error,
2355+ DBUS_TYPE_STRING, &goal,
2356+ DBUS_TYPE_INVALID))
2357+ {
2358+ old_goal = instance->properties.goal;
2359+ instance->properties.goal = strdup (goal);
2360+ ply_trace ("goal changed from '%s' to '%s'", old_goal, goal);
2361+ free (old_goal);
2362+ }
2363+ dbus_error_free (&error);
2364+ }
2365+ return DBUS_HANDLER_RESULT_HANDLED;
2366+}
2367+
2368+static DBusHandlerResult
2369+state_changed_handler (DBusConnection *connection, DBusMessage *message,
2370+ ply_upstart_monitor_t *monitor, const char *path)
2371+{
2372+ DBusError error;
2373+ const char *state;
2374+ ply_upstart_monitor_instance_t *instance;
2375+ char *old_state;
2376+
2377+ ply_trace ("got %s StateChanged", path);
2378+ instance = ply_hashtable_lookup (monitor->all_instances, (void *) path);
2379+ if (instance != NULL)
2380+ {
2381+ dbus_error_init (&error);
2382+ if (dbus_message_get_args (message, &error,
2383+ DBUS_TYPE_STRING, &state,
2384+ DBUS_TYPE_INVALID))
2385+ {
2386+ old_state = instance->properties.state;
2387+ instance->properties.state = strdup (state);
2388+ ply_trace ("state changed from '%s' to '%s'", old_state, state);
2389+ if (strcmp (state, "starting") == 0)
2390+ {
2391+ /* Clear any old failed information. */
2392+ instance->properties.failed = 0;
2393+ instance->call_failed = false;
2394+ }
2395+ if (instance_is_initialized (instance))
2396+ {
2397+ if (monitor->state_changed_handler)
2398+ monitor->state_changed_handler (monitor->state_changed_data,
2399+ old_state,
2400+ &instance->job->properties,
2401+ &instance->properties);
2402+ }
2403+ else
2404+ instance->state_changed = true;
2405+ free (old_state);
2406+ }
2407+ dbus_error_free (&error);
2408+ }
2409+ return DBUS_HANDLER_RESULT_HANDLED;
2410+}
2411+
2412+static DBusHandlerResult
2413+failed_handler (DBusConnection *connection, DBusMessage *message,
2414+ ply_upstart_monitor_t *monitor, const char *path)
2415+{
2416+ DBusError error;
2417+ ply_upstart_monitor_instance_t *instance;
2418+ dbus_int32_t failed_status;
2419+
2420+ ply_trace ("got %s Failed", path);
2421+ instance = ply_hashtable_lookup (monitor->all_instances, (void *) path);
2422+ if (instance != NULL)
2423+ {
2424+ dbus_error_init (&error);
2425+ if (dbus_message_get_args (message, &error,
2426+ DBUS_TYPE_INT32, &failed_status,
2427+ DBUS_TYPE_INVALID))
2428+ {
2429+ instance->properties.failed = failed_status;
2430+ if (instance_is_initialized (instance))
2431+ {
2432+ if (monitor->failed_handler)
2433+ monitor->failed_handler (monitor->failed_data,
2434+ &instance->job->properties,
2435+ &instance->properties,
2436+ (int) failed_status);
2437+ }
2438+ else
2439+ instance->call_failed = true;
2440+ }
2441+ dbus_error_free (&error);
2442+ }
2443+ return DBUS_HANDLER_RESULT_HANDLED;
2444+}
2445+
2446+static DBusHandlerResult
2447+message_handler (DBusConnection *connection, DBusMessage *message, void *data)
2448+{
2449+ ply_upstart_monitor_t *monitor = data;
2450+ const char *path;
2451+
2452+ assert (connection != NULL);
2453+ assert (message != NULL);
2454+ assert (monitor != NULL);
2455+
2456+ path = dbus_message_get_path (message);
2457+ if (path == NULL)
2458+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
2459+
2460+ if (dbus_message_is_signal (message, DBUS_INTERFACE_DBUS,
2461+ "NameOwnerChanged") &&
2462+ dbus_message_has_path (message, DBUS_PATH_DBUS) &&
2463+ dbus_message_has_sender (message, DBUS_SERVICE_DBUS))
2464+ return name_owner_changed_handler (connection, message, monitor);
2465+
2466+ if (dbus_message_is_signal (message, UPSTART_INTERFACE_0_6,
2467+ "JobAdded"))
2468+ return job_added_handler (connection, message, monitor);
2469+
2470+ if (dbus_message_is_signal (message, UPSTART_INTERFACE_0_6,
2471+ "JobRemoved"))
2472+ return job_removed_handler (connection, message, monitor);
2473+
2474+ if (dbus_message_is_signal (message, UPSTART_INTERFACE_0_6_JOB,
2475+ "InstanceAdded"))
2476+ return instance_added_handler (connection, message, monitor, path);
2477+
2478+ if (dbus_message_is_signal (message, UPSTART_INTERFACE_0_6_JOB,
2479+ "InstanceRemoved"))
2480+ return instance_removed_handler (connection, message, monitor, path);
2481+
2482+ if (dbus_message_is_signal (message, UPSTART_INTERFACE_0_6_INSTANCE,
2483+ "GoalChanged"))
2484+ return goal_changed_handler (connection, message, monitor, path);
2485+
2486+ if (dbus_message_is_signal (message, UPSTART_INTERFACE_0_6_INSTANCE,
2487+ "StateChanged"))
2488+ return state_changed_handler (connection, message, monitor, path);
2489+
2490+ if (dbus_message_is_signal (message, UPSTART_INTERFACE_0_6_INSTANCE,
2491+ "Failed"))
2492+ return failed_handler (connection, message, monitor, path);
2493+
2494+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
2495+}
2496+
2497+ply_upstart_monitor_t *
2498+ply_upstart_monitor_new (ply_event_loop_t *loop)
2499+{
2500+ DBusError error;
2501+ DBusConnection *connection;
2502+ ply_upstart_monitor_t *monitor;
2503+ char *rule;
2504+ DBusMessage *message;
2505+ const char *monitor_service = UPSTART_SERVICE;
2506+ DBusPendingCall *call;
2507+
2508+ dbus_error_init (&error);
2509+
2510+ /* Get a connection to the system bus and set it up to listen for messages
2511+ * from Upstart.
2512+ */
2513+ connection = dbus_bus_get (DBUS_BUS_SYSTEM, &error);
2514+ if (connection == NULL)
2515+ {
2516+ ply_error ("unable to connect to system bus: %s", error.message);
2517+ dbus_error_free (&error);
2518+ return NULL;
2519+ }
2520+ dbus_error_free (&error);
2521+
2522+ monitor = calloc (1, sizeof (ply_upstart_monitor_t));
2523+ monitor->connection = connection;
2524+ monitor->loop = NULL;
2525+ monitor->jobs = ply_hashtable_new (ply_hashtable_string_hash,
2526+ ply_hashtable_string_compare);
2527+ monitor->all_instances = ply_hashtable_new (ply_hashtable_string_hash,
2528+ ply_hashtable_string_compare);
2529+ monitor->state_changed_handler = NULL;
2530+ monitor->state_changed_data = NULL;
2531+ monitor->failed_handler = NULL;
2532+ monitor->failed_data = NULL;
2533+ monitor->dispatch_fd = -1;
2534+
2535+ if (!dbus_connection_add_filter (connection, message_handler, monitor, NULL))
2536+ {
2537+ ply_error ("unable to add filter to system bus connection");
2538+ ply_upstart_monitor_free (monitor);
2539+ return NULL;
2540+ }
2541+
2542+ asprintf (&rule, "type='%s',sender='%s',path='%s',"
2543+ "interface='%s',member='%s',arg0='%s'",
2544+ "signal", DBUS_SERVICE_DBUS, DBUS_PATH_DBUS,
2545+ DBUS_INTERFACE_DBUS, "NameOwnerChanged", UPSTART_SERVICE);
2546+ dbus_bus_add_match (connection, rule, &error);
2547+ free (rule);
2548+ if (dbus_error_is_set (&error))
2549+ {
2550+ ply_error ("unable to add match rule to system bus connection: %s",
2551+ error.message);
2552+ ply_upstart_monitor_free (monitor);
2553+ dbus_error_free (&error);
2554+ return NULL;
2555+ }
2556+
2557+ asprintf (&rule, "type='%s',sender='%s'", "signal", UPSTART_SERVICE);
2558+ dbus_bus_add_match (connection, rule, &error);
2559+ free (rule);
2560+ if (dbus_error_is_set (&error))
2561+ {
2562+ ply_error ("unable to add match rule to system bus connection: %s",
2563+ error.message);
2564+ ply_upstart_monitor_free (monitor);
2565+ dbus_error_free (&error);
2566+ return NULL;
2567+ }
2568+
2569+ /* Start the state machine going: find out the current owner of the
2570+ * well-known Upstart name.
2571+ * Ignore errors: the worst case is that we don't get any messages back
2572+ * and our state machine does nothing.
2573+ */
2574+ ply_trace ("calling GetNameOwner");
2575+ message = dbus_message_new_method_call (DBUS_SERVICE_DBUS, DBUS_PATH_DBUS,
2576+ DBUS_INTERFACE_DBUS, "GetNameOwner");
2577+ dbus_message_append_args (message,
2578+ DBUS_TYPE_STRING, &monitor_service,
2579+ DBUS_TYPE_INVALID);
2580+ dbus_connection_send_with_reply (connection, message, &call, -1);
2581+ dbus_message_unref (message);
2582+ if (call != NULL)
2583+ dbus_pending_call_set_notify (call,
2584+ (DBusPendingCallNotifyFunction)
2585+ on_get_name_owner_finished,
2586+ monitor,
2587+ NULL);
2588+
2589+ if (loop != NULL)
2590+ ply_upstart_monitor_connect_to_event_loop (monitor, loop);
2591+
2592+ return monitor;
2593+}
2594+
2595+void
2596+ply_upstart_monitor_free (ply_upstart_monitor_t *monitor)
2597+{
2598+ if (monitor == NULL)
2599+ return;
2600+
2601+ ply_hashtable_free (monitor->all_instances);
2602+ ply_hashtable_free (monitor->jobs);
2603+ dbus_connection_unref (monitor->connection);
2604+ if (monitor->dispatch_fd >= 0)
2605+ close (monitor->dispatch_fd);
2606+ free (monitor);
2607+}
2608+
2609+static void
2610+read_watch_handler (void *data, int fd)
2611+{
2612+ DBusWatch *watch = data;
2613+
2614+ assert (watch != NULL);
2615+
2616+ dbus_watch_handle (watch, DBUS_WATCH_READABLE);
2617+}
2618+
2619+static void
2620+write_watch_handler (void *data, int fd)
2621+{
2622+ DBusWatch *watch = data;
2623+
2624+ assert (watch != NULL);
2625+
2626+ dbus_watch_handle (watch, DBUS_WATCH_WRITABLE);
2627+}
2628+
2629+static dbus_bool_t
2630+add_watch (DBusWatch *watch, void *data)
2631+{
2632+ ply_upstart_monitor_t *monitor = data;
2633+ unsigned int flags;
2634+ int fd;
2635+ ply_event_loop_fd_status_t status;
2636+ ply_fd_watch_t *read_watch_event = NULL, *write_watch_event = NULL;
2637+
2638+ assert (monitor != NULL);
2639+ assert (watch != NULL);
2640+
2641+ if (!dbus_watch_get_enabled (watch))
2642+ return TRUE;
2643+
2644+ assert (dbus_watch_get_data (watch) == NULL);
2645+
2646+ flags = dbus_watch_get_flags (watch);
2647+ fd = dbus_watch_get_unix_fd (watch);
2648+
2649+ if (flags & DBUS_WATCH_READABLE)
2650+ {
2651+ status = PLY_EVENT_LOOP_FD_STATUS_HAS_DATA;
2652+ read_watch_event = ply_event_loop_watch_fd (monitor->loop, fd, status,
2653+ read_watch_handler, NULL,
2654+ watch);
2655+ if (read_watch_event == NULL)
2656+ return FALSE;
2657+ dbus_watch_set_data (watch, read_watch_event, NULL);
2658+ }
2659+
2660+ if (flags & DBUS_WATCH_WRITABLE)
2661+ {
2662+ status = PLY_EVENT_LOOP_FD_STATUS_CAN_TAKE_DATA;
2663+ write_watch_event = ply_event_loop_watch_fd (monitor->loop, fd, status,
2664+ write_watch_handler, NULL,
2665+ watch);
2666+ if (write_watch_event == NULL)
2667+ {
2668+ if (read_watch_event != NULL)
2669+ ply_event_loop_stop_watching_fd (monitor->loop, read_watch_event);
2670+ return FALSE;
2671+ }
2672+ dbus_watch_set_data (watch, write_watch_event, NULL);
2673+ }
2674+
2675+ return TRUE;
2676+}
2677+
2678+static void
2679+remove_watch (DBusWatch *watch, void *data)
2680+{
2681+ ply_upstart_monitor_t *monitor = data;
2682+ ply_fd_watch_t *watch_event;
2683+
2684+ assert (monitor != NULL);
2685+ assert (watch != NULL);
2686+
2687+ watch_event = dbus_watch_get_data (watch);
2688+ if (watch_event == NULL)
2689+ return;
2690+
2691+ ply_event_loop_stop_watching_fd (monitor->loop, watch_event);
2692+
2693+ dbus_watch_set_data (watch, NULL, NULL);
2694+}
2695+
2696+static void
2697+toggled_watch (DBusWatch *watch, void *data)
2698+{
2699+ if (dbus_watch_get_enabled (watch))
2700+ add_watch (watch, data);
2701+ else
2702+ remove_watch (watch, data);
2703+}
2704+
2705+static ply_upstart_monitor_timeout_t *
2706+timeout_user_data_new (ply_upstart_monitor_t *monitor, DBusTimeout *timeout)
2707+{
2708+ ply_upstart_monitor_timeout_t *monitor_timeout;
2709+
2710+ monitor_timeout = calloc (1, sizeof (ply_upstart_monitor_timeout_t));
2711+ monitor_timeout->monitor = monitor;
2712+ monitor_timeout->timeout = timeout;
2713+
2714+ return monitor_timeout;
2715+}
2716+
2717+static void
2718+timeout_user_data_free (void *data)
2719+{
2720+ ply_upstart_monitor_timeout_t *monitor_timeout = data;
2721+
2722+ free (monitor_timeout);
2723+}
2724+
2725+static void
2726+timeout_handler (void *data, ply_event_loop_t *loop)
2727+{
2728+ ply_upstart_monitor_timeout_t *monitor_timeout = data;
2729+
2730+ assert (monitor_timeout != NULL);
2731+
2732+ dbus_timeout_handle (monitor_timeout->timeout);
2733+}
2734+
2735+static dbus_bool_t
2736+add_timeout (DBusTimeout *timeout, void *data)
2737+{
2738+ ply_upstart_monitor_t *monitor = data;
2739+ int interval;
2740+ ply_upstart_monitor_timeout_t *monitor_timeout;
2741+
2742+ assert (monitor != NULL);
2743+ assert (timeout != NULL);
2744+
2745+ if (!dbus_timeout_get_enabled (timeout))
2746+ return TRUE;
2747+
2748+ interval = dbus_timeout_get_interval (timeout) * 1000;
2749+
2750+ monitor_timeout = timeout_user_data_new (monitor, timeout);
2751+
2752+ ply_event_loop_watch_for_timeout (monitor->loop, (double) interval,
2753+ timeout_handler, monitor_timeout);
2754+
2755+ dbus_timeout_set_data (timeout, monitor_timeout, timeout_user_data_free);
2756+
2757+ return TRUE;
2758+}
2759+
2760+static void
2761+remove_timeout (DBusTimeout *timeout, void *data)
2762+{
2763+ ply_upstart_monitor_t *monitor = data;
2764+ ply_upstart_monitor_timeout_t *monitor_timeout;
2765+
2766+ assert (monitor != NULL);
2767+ assert (timeout != NULL);
2768+
2769+ monitor_timeout = dbus_timeout_get_data (timeout);
2770+ if (monitor_timeout == NULL)
2771+ return;
2772+
2773+ ply_event_loop_stop_watching_for_timeout (monitor->loop,
2774+ timeout_handler, monitor_timeout);
2775+
2776+ dbus_timeout_set_data (timeout, NULL, NULL);
2777+}
2778+
2779+static void
2780+toggled_timeout (DBusTimeout *timeout, void *data)
2781+{
2782+ if (dbus_timeout_get_enabled (timeout))
2783+ add_timeout (timeout, data);
2784+ else
2785+ remove_timeout (timeout, data);
2786+}
2787+
2788+static void
2789+dispatch_status (DBusConnection *connection, DBusDispatchStatus new_status,
2790+ void *data)
2791+{
2792+ ply_upstart_monitor_t *monitor = data;
2793+ uint64_t event_payload;
2794+
2795+ assert (monitor != NULL);
2796+
2797+ if (new_status != DBUS_DISPATCH_DATA_REMAINS)
2798+ return;
2799+
2800+ /* wake up event loop */
2801+ event_payload = 1;
2802+ ply_write (monitor->dispatch_fd, &event_payload, sizeof (event_payload));
2803+}
2804+
2805+static void
2806+dispatch (void *data, int fd)
2807+{
2808+ ply_upstart_monitor_t *monitor = data;
2809+ uint64_t event_payload;
2810+
2811+ assert (monitor != NULL);
2812+
2813+ /* reset eventfd to zero */
2814+ ply_read (fd, &event_payload, sizeof (event_payload));
2815+
2816+ while (dbus_connection_dispatch (monitor->connection) ==
2817+ DBUS_DISPATCH_DATA_REMAINS)
2818+ ;
2819+}
2820+
2821+bool
2822+ply_upstart_monitor_connect_to_event_loop (ply_upstart_monitor_t *monitor,
2823+ ply_event_loop_t *loop)
2824+{
2825+ ply_fd_watch_t *dispatch_event = NULL;
2826+ uint64_t event_payload;
2827+
2828+ assert (monitor != NULL);
2829+
2830+ monitor->loop = loop;
2831+ monitor->dispatch_fd = -1;
2832+
2833+ if (!dbus_connection_set_watch_functions (monitor->connection,
2834+ add_watch,
2835+ remove_watch,
2836+ toggled_watch,
2837+ monitor, NULL))
2838+ goto err;
2839+
2840+ if (!dbus_connection_set_timeout_functions (monitor->connection,
2841+ add_timeout,
2842+ remove_timeout,
2843+ toggled_timeout,
2844+ monitor, NULL))
2845+ goto err;
2846+
2847+ monitor->dispatch_fd = eventfd (0, EFD_CLOEXEC | EFD_NONBLOCK);
2848+ if (monitor->dispatch_fd < 0)
2849+ goto err;
2850+ /* make sure we wake up to dispatch the first time through */
2851+ event_payload = 1;
2852+ ply_write (monitor->dispatch_fd, &event_payload, sizeof (event_payload));
2853+
2854+ dispatch_event = ply_event_loop_watch_fd (monitor->loop,
2855+ monitor->dispatch_fd,
2856+ PLY_EVENT_LOOP_FD_STATUS_HAS_DATA,
2857+ dispatch, NULL, monitor);
2858+ if (dispatch_event == NULL)
2859+ goto err;
2860+
2861+ dbus_connection_set_dispatch_status_function (monitor->connection,
2862+ dispatch_status,
2863+ monitor, NULL);
2864+
2865+ return true;
2866+
2867+err:
2868+ dbus_connection_set_watch_functions (monitor->connection,
2869+ NULL, NULL, NULL, NULL, NULL);
2870+ dbus_connection_set_timeout_functions (monitor->connection,
2871+ NULL, NULL, NULL, NULL, NULL);
2872+ dbus_connection_set_dispatch_status_function (monitor->connection,
2873+ NULL, NULL, NULL);
2874+ if (dispatch_event != NULL)
2875+ ply_event_loop_stop_watching_fd (monitor->loop, dispatch_event);
2876+ if (monitor->dispatch_fd >= 0)
2877+ {
2878+ close (monitor->dispatch_fd);
2879+ monitor->dispatch_fd = -1;
2880+ }
2881+ monitor->loop = NULL;
2882+ return false;
2883+}
2884+
2885+void
2886+ply_upstart_monitor_add_state_changed_handler (ply_upstart_monitor_t *monitor,
2887+ ply_upstart_monitor_state_changed_handler_t handler,
2888+ void *user_data)
2889+{
2890+ monitor->state_changed_handler = handler;
2891+ monitor->state_changed_data = user_data;
2892+}
2893+
2894+void
2895+ply_upstart_monitor_add_failed_handler (ply_upstart_monitor_t *monitor,
2896+ ply_upstart_monitor_failed_handler_t handler,
2897+ void *user_data)
2898+{
2899+ monitor->failed_handler = handler;
2900+ monitor->failed_data = user_data;
2901+}
2902+/* vim: set ts=4 sw=4 expandtab autoindent cindent cino={.5s,(0: */
2903
2904=== modified file 'debian/changelog'
2905--- debian/changelog 2014-03-06 17:52:51 +0000
2906+++ debian/changelog 2014-03-14 10:43:52 +0000
2907@@ -1,10 +1,32 @@
2908 plymouth (0.8.8-0ubuntu16) UNRELEASED; urgency=medium
2909
2910+ [ Steve Langasek ]
2911 * Fix debian/patches/tty1-after-boot.patch: when we have multiple
2912 non-default console options on the kernel commandline,
2913 local_console_terminal will not be set, so we should avoid the resulting
2914 assert. LP: #1160079, LP: #1235231.
2915
2916+ [ Dimitri John Ledkov ] LP: #1292458
2917+ * debian/patches/use-upstart-private-socket.patch: instead of using
2918+ system dbus, use private upstart socket in the plymouth-upstart-bridge.
2919+ * debian/plymouth.plymouth-upstart-bridge.upstart: start
2920+ plymouth-upstart-bridge on startup, and thus gather a more complete
2921+ boot.log.
2922+ * debian/patches/dont-bail-on-dummy-terms.patch: don't bail
2923+ plymouth-upstart-bridge if TERM is not set and/or running on a dummy
2924+ terminal, as we can run on those. This makes console-log useful in
2925+ lxc-containers and actually contain messages from upstart jobs
2926+ starting and stopping.
2927+ * debian/patches/no-print-empty-description.patch: do not store
2928+ description when dbus returns empty string, and thus stop printing
2929+ empty "Starting... done" messages. LP: #1185560.
2930+ * debian/plymouth.plymouth-upstart-bridge.upstart: update stop on
2931+ conditions to stop when plymouth-shutdown finishes.
2932+ * Make ubuntu-logo theme support scale factor, provide one plymouth
2933+ theme with scale 1 and another with scale 2, until scale factor can be
2934+ dynamically detected.
2935+ * Mark plymouth-upstart-bridge to respawn.
2936+
2937 -- Steve Langasek <steve.langasek@ubuntu.com> Tue, 04 Mar 2014 14:30:16 -0800
2938
2939 plymouth (0.8.8-0ubuntu15) trusty; urgency=medium
2940
2941=== modified file 'debian/control'
2942--- debian/control 2014-02-04 17:07:35 +0000
2943+++ debian/control 2014-03-14 10:43:52 +0000
2944@@ -178,7 +178,7 @@
2945
2946 Package: plymouth-theme-ubuntu-logo
2947 Architecture: any
2948-Depends: plymouth, plymouth-label, ${misc:Depends}, ${shlibs:Depends}
2949+Depends: plymouth, plymouth-label, ttf-ubuntu-font-family, ${misc:Depends}, ${shlibs:Depends}
2950 Provides: plymouth-theme
2951 Replaces: plymouth (<< 0.8.1-1~)
2952 Description: graphical boot animation and logger - ubuntu-logo theme
2953
2954=== added file 'debian/patches/dont-bail-on-dummy-terms.patch'
2955--- debian/patches/dont-bail-on-dummy-terms.patch 1970-01-01 00:00:00 +0000
2956+++ debian/patches/dont-bail-on-dummy-terms.patch 2014-03-14 10:43:52 +0000
2957@@ -0,0 +1,17 @@
2958+Description: don't bail plymouth-upstart-bridge if TERM is not set
2959+ and/or running on a dummy terminal, as we can run on those.
2960+Author: Dimitri John Ledkov <xnox@ubuntu.com>
2961+
2962+--- a/src/upstart-bridge/plymouth-upstart-bridge.c
2963++++ b/src/upstart-bridge/plymouth-upstart-bridge.c
2964+@@ -307,7 +307,9 @@
2965+ if (should_be_verbose && !ply_is_tracing ())
2966+ ply_toggle_tracing ();
2967+
2968+- setupterm (NULL, STDOUT_FILENO, NULL);
2969++ /* Don't bail on dummy/hardcopy terminals */
2970++ int errret=0;
2971++ setupterm (NULL, STDOUT_FILENO, &errret);
2972+
2973+ is_connected = ply_boot_client_connect (state.client,
2974+ (ply_boot_client_disconnect_handler_t)
2975
2976=== added file 'debian/patches/no-print-empty-description.patch'
2977--- debian/patches/no-print-empty-description.patch 1970-01-01 00:00:00 +0000
2978+++ debian/patches/no-print-empty-description.patch 2014-03-14 10:43:52 +0000
2979@@ -0,0 +1,14 @@
2980+Description: do not store empty descriptions
2981+Author: Dimitri John Ledkov <xnox@ubuntu.com>
2982+
2983+--- plymouth-0.8.8.orig/src/upstart-bridge/ply-upstart-monitor.c
2984++++ plymouth-0.8.8/src/upstart-bridge/ply-upstart-monitor.c
2985+@@ -273,7 +273,7 @@ on_get_all_job_properties_finished (DBus
2986+ DBUS_TYPE_STRING)
2987+ goto next_item;
2988+ dbus_message_iter_get_basic (&variant_iter, &description);
2989+- if (description != NULL)
2990++ if (description != NULL && description[0])
2991+ {
2992+ ply_trace ("description = '%s'", description);
2993+ job->properties.description = strdup (description);
2994
2995=== modified file 'debian/patches/series'
2996--- debian/patches/series 2013-12-02 04:53:37 +0000
2997+++ debian/patches/series 2014-03-14 10:43:52 +0000
2998@@ -13,3 +13,7 @@
2999 Miscellaneous-fixes-for-compiler-warnings.patch
3000 autoreconf.patch
3001 details-update-status.patch
3002+use-upstart-private-socket.patch
3003+dont-bail-on-dummy-terms.patch
3004+no-print-empty-description.patch
3005+ubuntu-logo-scale-factor-2.patch
3006
3007=== added file 'debian/patches/ubuntu-logo-scale-factor-2.patch'
3008--- debian/patches/ubuntu-logo-scale-factor-2.patch 1970-01-01 00:00:00 +0000
3009+++ debian/patches/ubuntu-logo-scale-factor-2.patch 2014-03-14 10:43:52 +0000
3010@@ -0,0 +1,1202 @@
3011+Description: Make ubuntu-logo theme support scale factor, provide one plymouth
3012+ theme with scale 1 and another with scale 2, until scale factor can be
3013+ dynamically detected.
3014+Author: Dimitri John Ledkov <xnox@ubuntu.com>
3015+
3016+--- a/themes/ubuntu-logo/Makefile.am
3017++++ b/themes/ubuntu-logo/Makefile.am
3018+@@ -1,6 +1,7 @@
3019+ themedir = $(datadir)/plymouth/themes/ubuntu-logo
3020+-nodist_theme_DATA = ubuntu-logo.plymouth
3021++nodist_theme_DATA = ubuntu-logo.plymouth ubuntu-logo-scale-2.plymouth
3022+ dist_theme_DATA = ubuntu-logo.script \
3023++ ubuntu-logo-scale-2.script \
3024+ ubuntu-logo.grub \
3025+ ubuntu_logo.png \
3026+ ubuntu_logo16.png \
3027+@@ -13,11 +14,23 @@
3028+
3029+
3030+
3031+-MAINTAINERCLEANFILES = Makefile.in ubuntu-logo.plymouth
3032+-CLEANFILES = ubuntu-logo.plymouth
3033++MAINTAINERCLEANFILES = Makefile.in ubuntu-logo.plymouth ubuntu-logo-scale-2.plymouth ubuntu-logo.script ubuntu-logo-scale-2.script
3034++CLEANFILES = ubuntu-logo.plymouth ubuntu-logo-scale-2.plymouth ubuntu-logo.script ubuntu-logo-scale-2.script
3035+
3036+ ubuntu-logo.plymouth: $(srcdir)/ubuntu-logo.plymouth.in
3037+- sed -e 's,[@]PLYMOUTH_THEME_PATH[@],$(PLYMOUTH_THEME_PATH),g' \
3038++ sed -e 's,[@]PLYMOUTH_THEME_PATH[@],$(PLYMOUTH_THEME_PATH),g;s,[@]EXTRA_NAME[@],,g;s,[@]SCRIPT_NAME[@],ubuntu-logo,g' \
3039+ $(srcdir)/ubuntu-logo.plymouth.in > ubuntu-logo.plymouth
3040+
3041+-EXTRA_DIST = ubuntu-logo.plymouth.in
3042++ubuntu-logo-scale-2.plymouth: $(srcdir)/ubuntu-logo.plymouth.in
3043++ sed -e 's,[@]PLYMOUTH_THEME_PATH[@],$(PLYMOUTH_THEME_PATH),g;s,[@]EXTRA_NAME[@],(Scale x2),g;s,[@]SCRIPT_NAME[@],ubuntu-logo-scale-2,g' \
3044++ $(srcdir)/ubuntu-logo.plymouth.in > ubuntu-logo-scale-2.plymouth
3045++
3046++ubuntu-logo.script: $(srcdir)/ubuntu-logo.script.in
3047++ sed -e 's,[@]SCALEFACTOR[@],1,g' \
3048++ $(srcdir)/ubuntu-logo.script.in > ubuntu-logo.script
3049++
3050++ubuntu-logo-scale-2.script: $(srcdir)/ubuntu-logo.script.in
3051++ sed -e 's,[@]SCALEFACTOR[@],2,g' \
3052++ $(srcdir)/ubuntu-logo.script.in > ubuntu-logo-scale-2.script
3053++
3054++EXTRA_DIST = ubuntu-logo.plymouth.in ubuntu-logo.script.in
3055+--- a/themes/ubuntu-logo/ubuntu-logo.plymouth.in
3056++++ b/themes/ubuntu-logo/ubuntu-logo.plymouth.in
3057+@@ -1,8 +1,8 @@
3058+ [Plymouth Theme]
3059+-Name=Ubuntu Logo
3060++Name=Ubuntu Logo @EXTRA_NAME@
3061+ Description=A theme that features a blank background with a logo.
3062+ ModuleName=script
3063+
3064+ [script]
3065+ ImageDir=@PLYMOUTH_THEME_PATH@/ubuntu-logo
3066+-ScriptFile=@PLYMOUTH_THEME_PATH@/ubuntu-logo/ubuntu-logo.script
3067++ScriptFile=@PLYMOUTH_THEME_PATH@/ubuntu-logo/@SCRIPT_NAME@.script
3068+--- /dev/null
3069++++ b/themes/ubuntu-logo/ubuntu-logo.script.in
3070+@@ -0,0 +1,1142 @@
3071++# ubuntu-logo.script - boot splash plugin
3072++#
3073++# Copyright (C) 2009 Canonical Ltd.
3074++#
3075++# This program is free software; you can redistribute it and/or modify
3076++# it under the terms of the GNU General Public License as published by
3077++# the Free Software Foundation; either version 2, or (at your option)
3078++# any later version.
3079++#
3080++# This program is distributed in the hope that it will be useful,
3081++# but WITHOUT ANY WARRANTY; without even the implied warranty of
3082++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
3083++# GNU General Public License for more details.
3084++#
3085++# You should have received a copy of the GNU General Public License
3086++# along with this program; if not, write to the Free Software
3087++# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
3088++# 02111-1307, USA.
3089++#
3090++# Written by: Alberto Milone <alberto.milone@canonical.com>
3091++#
3092++# Based on the example provided with the "script plugin" written by:
3093++# Charlie Brej <cbrej@cs.man.ac.uk>
3094++#
3095++# Question stuff written by: Markus Waas <mail@markuswaas.de>
3096++#
3097++#
3098++
3099++# Set the text colour in (rgb / 256)
3100++text_colour.red = 1.0;
3101++text_colour.green = 1.0;
3102++text_colour.blue = 1.0;
3103++
3104++# Tinted text #988592
3105++tinted_text_colour.red = 0.59;
3106++tinted_text_colour.green = 0.52;
3107++tinted_text_colour.blue = 0.57;
3108++
3109++# Action Text - #ffffff - RGB 255 255 255
3110++action_text_colour.red = 1.0;
3111++action_text_colour.green = 1.0;
3112++action_text_colour.blue = 1.0;
3113++
3114++# Orange - #ff4012 - RGB 255 64 18
3115++debugsprite = Sprite();
3116++debugsprite_bottom = Sprite();
3117++debugsprite_medium = Sprite();
3118++
3119++# Ubuntu Font
3120++ubuntufont = "Ubuntu 11";
3121++ubuntualignment = "center";
3122++
3123++# Scale factor
3124++scalefactor = @SCALEFACTOR@;
3125++
3126++# are we currently prompting for a password?
3127++prompt_active = 0;
3128++
3129++# Generic scalable image loader
3130++fun LoadScaleImage (imagepath) {
3131++ image = Image (imagepath);
3132++ image = image.Scale (image.GetWidth() * scalefactor, image.GetHeight() * scalefactor);
3133++ return image;
3134++}
3135++
3136++# General purpose function to create text
3137++fun WriteText (text, colour) {
3138++ image = Image.Text (text, colour.red, colour.green, colour.blue, color.alpha, ubuntufont, ubuntualignment);
3139++ image = image.Scale (image.GetWidth() * scalefactor, image.GetHeight() * scalefactor);
3140++ return image;
3141++}
3142++
3143++fun ImageToText (text) {
3144++ image = WriteText (text, text_colour);
3145++ return image;
3146++}
3147++
3148++fun ImageToTintedText (text) {
3149++ image = WriteText (text, tinted_text_colour);
3150++ return image;
3151++}
3152++
3153++fun ImageToActionText (text) {
3154++ image = WriteText (text, action_text_colour);
3155++ return image;
3156++}
3157++
3158++fun Debug(text) {
3159++ debugsprite.SetImage(ImageToText (text));
3160++}
3161++
3162++fun DebugBottom(text) {
3163++ debugsprite_bottom.SetImage(ImageToText (text));
3164++ debugsprite_bottom.SetPosition(0, (Window.GetHeight (0) - 20), 1);
3165++}
3166++
3167++fun DebugMedium(text) {
3168++ debugsprite_medium.SetImage(ImageToText (text));
3169++ debugsprite_medium.SetPosition(0, (Window.GetHeight (0) - 60), 1);
3170++}
3171++
3172++fun TextYOffset() {
3173++ local.y;
3174++ local.text_height;
3175++ local.min_height;
3176++
3177++ # Put the 1st line below the logo + some spacing
3178++ y = logo.y + logo.height + (progress_indicator.bullet_height * 7 ); # + logo_spacing;
3179++
3180++ text_height = first_line_height * 7.5;
3181++
3182++ min_height = Window.GetHeight();
3183++ if (y + text_height > min_height)
3184++ y = min_height - text_height;
3185++
3186++ if (y < progress_indicator.y + progress_indicator.height)
3187++ return progress_indicator.y + progress_indicator.height;
3188++ return y;
3189++}
3190++
3191++#------------------------------String functions-------------------------------
3192++
3193++# This is the equivalent for strstr()
3194++fun StringString(string, substring) {
3195++ start = 0;
3196++ while (String(string).CharAt (start)) {
3197++ walk = 0;
3198++ while (String(substring).CharAt (walk) == String(string).CharAt (start + walk) ) {
3199++ walk++;
3200++ if (!String(substring).CharAt (walk)) return start;
3201++ }
3202++ start++;
3203++ }
3204++
3205++ return NULL;
3206++}
3207++
3208++fun StringLength (string) {
3209++ index = 0;
3210++ while (String(string).CharAt(index)) index++;
3211++ return index;
3212++}
3213++
3214++fun StringCopy (source, beginning, end) {
3215++ local.destination = "";
3216++ for (index = beginning; ( ( (end == NULL) || (index <= end) ) && (String(source).CharAt(index)) ); index++) {
3217++ local.destination += String(source).CharAt(index);
3218++ }
3219++
3220++ return local.destination;
3221++}
3222++
3223++fun StringReplace (source, pattern, replacement) {
3224++ local.found = StringString(source, pattern);
3225++ if (local.found == NULL)
3226++ return source;
3227++
3228++ local.new_string = StringCopy (source, 0, local.found - 1) +
3229++ replacement +
3230++ StringCopy (source, local.found + StringLength(pattern), NULL);
3231++
3232++ return local.new_string;
3233++}
3234++
3235++# it makes sense to use it only for
3236++# numbers up to 100
3237++fun StringToInteger (str) {
3238++ int = -1;
3239++ for (i=0; i<=100; i++) {
3240++ if (i+"" == str) {
3241++ int = i;
3242++ break;
3243++ }
3244++ }
3245++ return int;
3246++}
3247++
3248++#-----------------------------------------------------------------------------
3249++# Previous background colour
3250++# #300a24 --> 0.19, 0.04, 0.14
3251++# New background colour
3252++# #2c001e --> 0.16, 0.00, 0.12
3253++#
3254++Window.SetBackgroundTopColor (0.16, 0.00, 0.12); # Nice colour on top of the screen fading to
3255++Window.SetBackgroundBottomColor (0.16, 0.00, 0.12); # an equally nice colour on the bottom
3256++
3257++bits_per_pixel = Window.GetBitsPerPixel ();
3258++if (bits_per_pixel == 4) {
3259++ logo_filename = "ubuntu_logo16.png";
3260++ progress_dot_off_filename = "progress_dot_off16.png";
3261++ progress_dot_on_filename = "progress_dot_on16.png";
3262++ password_field_filename = "password_field16.png";
3263++ question_field_filename = "password_field16.png";
3264++} else {
3265++ logo_filename = "ubuntu_logo.png";
3266++ progress_dot_off_filename = "progress_dot_off.png";
3267++ progress_dot_on_filename = "progress_dot_on.png";
3268++ password_field_filename = "password_field.png";
3269++ question_field_filename = "password_field.png";
3270++}
3271++
3272++logo.image = LoadScaleImage (logo_filename);
3273++logo.sprite = Sprite ();
3274++logo.sprite.SetImage (logo.image);
3275++logo.width = logo.image.GetWidth ();
3276++logo.height = logo.image.GetHeight ();
3277++logo.x = Window.GetX () + Window.GetWidth () / 2 - logo.width / 2;
3278++logo.y = Window.GetY () + Window.GetHeight () / 2 - logo.height;
3279++logo.z = 1000;
3280++logo.sprite.SetX (logo.x);
3281++logo.sprite.SetY (logo.y);
3282++logo.sprite.SetZ (logo.z);
3283++logo.sprite.SetOpacity (1);
3284++
3285++# Spacing below the logo - in pixels
3286++logo_spacing = logo.height * 4;
3287++
3288++message_notification[0].image = ImageToTintedText ("");
3289++message_notification[1].image = ImageToTintedText ("");
3290++fsck_notification.image = ImageToActionText ("");
3291++
3292++status = "normal";
3293++
3294++progress_indicator.bullet_off = LoadScaleImage (progress_dot_off_filename);
3295++progress_indicator.bullet_on = LoadScaleImage (progress_dot_on_filename);
3296++progress_indicator.bullet_width = progress_indicator.bullet_off.GetWidth ();
3297++progress_indicator.bullet_height = progress_indicator.bullet_off.GetHeight ();
3298++progress_indicator.bullet_hspacing = progress_indicator.bullet_width * 1.1;
3299++progress_indicator.width = progress_indicator.bullet_width * 5;
3300++progress_indicator.height = progress_indicator.bullet_height;
3301++progress_indicator.y = logo.y + logo.height + (logo.height / 4);
3302++progress_indicator.x = Window.GetX () + Window.GetWidth () / 2 - progress_indicator.width / 2; # logo.x + 26;
3303++
3304++# use a fixed string with ascending and descending stems to calibrate the
3305++# bounding box for the first message, so the messages below don't move up
3306++# and down according to *their* height.
3307++first_line_height = ImageToTintedText ("AfpqtM").GetHeight();
3308++
3309++# if the user has a 640x480 or 800x600 display, we can't quite fit everything
3310++# (including passphrase prompts) with the target spacing, so scoot the text up
3311++# a bit if needed.
3312++top_of_the_text = TextYOffset();
3313++
3314++#-----------------------------------------Logo functions------------------------------
3315++
3316++# Call this when updating the screen
3317++fun draw_logo () {
3318++ logo.sprite.SetX (logo.x);
3319++ logo.sprite.SetY (logo.y);
3320++ logo.sprite.SetZ (logo.z);
3321++ logo.sprite.SetOpacity (1);
3322++}
3323++
3324++
3325++#-----------------------------------------Progress Indicator--------------------------
3326++fun set_progress_indicator () {
3327++
3328++
3329++ # Here we assume that we can store half bullets on each half of the screen
3330++ # together with some spacing
3331++ local.x = progress_indicator.x;
3332++
3333++ for (index = 0; index <= 4; index++) {
3334++ # Set the "off" bullets
3335++ progress_indicator.bullets_off[index].sprite = Sprite (progress_indicator.bullet_off);
3336++ progress_indicator.bullets_off[index].sprite.SetPosition (local.x, progress_indicator.y, 1000);
3337++ progress_indicator.bullets_off[index].x = local.x;
3338++ progress_indicator.bullets_off[index].y = progress_indicator.y;
3339++ progress_indicator.bullets_off[index].sprite.SetOpacity (1);
3340++
3341++ #local.debug_medium_string = "Progress indicator " + index + ": x = " + progress_indicator.bullets_off[index].x +
3342++ # ", y = " + progress_indicator.bullets_off[index].y + ", logo width = " + logo.width +
3343++ # ", logo height = " + logo.height + " " + screen_width + " " + screen_height;
3344++ #
3345++ #(index % 2) && DebugMedium (local.debug_medium_string) || DebugBottom (local.debug_medium_string);
3346++
3347++ # Set the "on" bullets on top of the "off" bullets and make them transparent
3348++ progress_indicator.bullets_on[index].sprite = Sprite (progress_indicator.bullet_on);
3349++ progress_indicator.bullets_on[index].x = progress_indicator.bullets_off[index].x;
3350++ progress_indicator.bullets_on[index].y = progress_indicator.bullets_off[index].y;
3351++ progress_indicator.bullets_on[index].sprite.SetPosition (progress_indicator.bullets_on[index].x, progress_indicator.bullets_on[index].y, 10000);
3352++
3353++ progress_indicator.bullets_on[index].sprite.SetOpacity (0);
3354++
3355++ local.x += progress_indicator.bullet_hspacing;
3356++ }
3357++ #local.debug_string = "Progress indicator: x1 = " + progress_indicator.x + ", x2 = " + local.x + ", y = " + progress_indicator.y +
3358++ # ", x logo = " + logo.x + ", y logo = " + logo.y + ", indicator width = " + progress_indicator.width;
3359++ #Debug(progress_indicator.bullets_off[0].x);
3360++}
3361++
3362++
3363++# We have 2 bullets, one on top of the other:
3364++# The white one is on top of the red one and the former should
3365++# slowly fade so as to get a nice transition effect.
3366++fun switch_on_bullet (bullets_off, bullets_on, bullet_number, opacity) {
3367++ local.x = bullets_on[bullet_number].x;
3368++ local.y = bullets_on[bullet_number].y;
3369++ local.z = bullets_on[bullet_number].z;
3370++
3371++ # Hide the bullets which are off
3372++ bullets_off[bullet_number].sprite.SetOpacity (0);
3373++
3374++ # Show the bullets which are on
3375++ bullets_on[bullet_number].sprite.SetPosition (local.x, local.y, local.z);
3376++ bullets_on[bullet_number].sprite.SetOpacity (opacity);
3377++
3378++ # Bump the number of times we have switched on bullets
3379++ global.times_bullets_switched++;
3380++}
3381++
3382++fun switch_off_bullets () {
3383++ # Debug("Switching off progress indicator");
3384++
3385++ set_progress_indicator ();
3386++ global.times_bullets_switched = 0;
3387++ global.on_off = 1;
3388++}
3389++
3390++# This is something that we can call when we exit
3391++fun switch_on_bullets () {
3392++ # Debug("Switching off progress indicator");
3393++ if (!global.progress_indicator.bullets_on) set_progress_indicator ();
3394++ local = global.progress_indicator;
3395++
3396++ for (index = 0; bullets_on[index]; index++) {
3397++ switch_on_bullet (bullets_off, bullets_on, index, 1.0);
3398++ }
3399++}
3400++
3401++
3402++# Implement in boot progress callback
3403++fun animate_progress_indicator (progress, time) {
3404++ if (global.progress_time == NULL) {
3405++ global.progress_time = progress; #time;
3406++ switch_off_bullets ();
3407++ }
3408++
3409++# Debug ("progress = " + progress + ", time = " + time + " times switched = " + global.times_bullets_switched + " on_off " + global.on_off);
3410++
3411++# if (global.times_bullets_switched == NULL)
3412++# global.times_bullets_switched = 5;
3413++
3414++# if (global.on_off == NULL)
3415++# global.on_off = 0;
3416++
3417++ if ((progress - global.progress_time) >= 1.0) {
3418++ global.progress_time = progress;
3419++
3420++ if (global.times_bullets_switched == 5) {
3421++ # Change which bullets are switched on
3422++ # and which ones are switched off
3423++ global.on_off = !global.on_off;
3424++ global.times_bullets_switched = 0;
3425++ }
3426++
3427++ if (global.on_off) {
3428++ switch_on_bullet (progress_indicator.bullets_off, progress_indicator.bullets_on,
3429++ global.times_bullets_switched, 1.0);
3430++ }
3431++ else {
3432++ switch_on_bullet (progress_indicator.bullets_on, progress_indicator.bullets_off,
3433++ global.times_bullets_switched, 1.0);
3434++ }
3435++ }
3436++
3437++
3438++ # Start setting bullets to "on" with translucency
3439++# for (index = 0; index <= 5; index++) {
3440++# opacity = 0.0;
3441++# while (opacity <= 1.0) {
3442++# switch_on_bullet (progress_indicator.bullets_off, progress_indicator.bullets_on,
3443++# index, opacity);
3444++# opacity += 0.1;
3445++# }
3446++# }
3447++}
3448++
3449++
3450++#-----------------------------------------Label utility functions---------------------
3451++
3452++# label should be either a string or NULL
3453++# Images for n lines will be created and returned as items of the
3454++# message_label array
3455++#
3456++fun get_message_label (label, is_fake, is_action_line) {
3457++ # Debug("Get Label position");
3458++ local.message_label;
3459++
3460++ if (is_fake)
3461++ # Create a fake label so as to get the y coordinate of
3462++ # a standard-length label.
3463++ local.message_image = ImageToTintedText ("This is a fake message");
3464++ else
3465++ local.message_image = (is_action_line) && ImageToActionText (label) || ImageToTintedText (label);
3466++
3467++ message_label.width = message_image.GetWidth ();
3468++ message_label.height = message_image.GetHeight ();
3469++
3470++ # Center the line horizontally
3471++ message_label.x = Window.GetX () + Window.GetWidth () / 2 - message_label.width / 2;
3472++
3473++ message_label.y = top_of_the_text;
3474++
3475++ # Put the 2nd line below the fsck line
3476++ if (is_action_line) {
3477++ local.fsck_label.y = message_label.y + (first_line_height + first_line_height / 2);
3478++ message_label.y = local.fsck_label.y + (first_line_height * 2);
3479++ }
3480++
3481++ # Debug("action label x = " + message_label.x + " y = " + message_label.y );
3482++
3483++# message_debug = "msg_x = " + message_label.x + " msg_y = " + message_label.y +
3484++# "msg_width = " + message_label.width + " msg_height = " +
3485++# message_label.height + " message = " + label;
3486++# Debug(message_debug);
3487++
3488++ return message_label;
3489++
3490++}
3491++
3492++# Create an fsck label and/or get its position
3493++fun get_fsck_label (label, is_fake) {
3494++ # Debug("Get Label position");
3495++ local.fsck_label = global.progress_label;
3496++
3497++ if (is_fake)
3498++ fsck_label.image = ImageToTintedText ("This is a fake message");
3499++ else
3500++ fsck_label.image = ImageToTintedText (label);
3501++
3502++ fsck_label.width = fsck_label.image.GetWidth ();
3503++ fsck_label.height = fsck_label.image.GetHeight ();
3504++
3505++ # Centre the label horizontally
3506++ fsck_label.x = Window.GetX () + Window.GetWidth () / 2 - fsck_label.width / 2;
3507++
3508++ local.first_label = get_message_label (label, 1, 0);
3509++
3510++ # Place the label below the 1st message line
3511++ fsck_label.y = local.first_label.y + local.first_label.height + (local.first_label.height / 2);
3512++
3513++# message_debug = "msg_x = " + fsck_label.x + " msg_y = " + fsck_label.y +
3514++# "msg_width = " + fsck_label.width + " msg_height = " +
3515++# fsck_label.height + " message = " + label;
3516++# Debug(message_debug);
3517++
3518++ return fsck_label;
3519++}
3520++
3521++#-----------------------------------------Message stuff --------------------------------
3522++#
3523++
3524++# Set up a message label
3525++#
3526++# NOTE: this is called when doing something like 'plymouth message "hello world"'
3527++#
3528++fun setup_message (message_text, x, y, z, index) {
3529++ # Debug("Message setup");
3530++ global.message_notification[index].image = (index) && ImageToActionText (message_text) || ImageToTintedText (message_text);
3531++
3532++ # Set up the text message, if any
3533++ message_notification[index].x = x;
3534++ message_notification[index].y = y;
3535++ message_notification[index].z = z;
3536++
3537++ message_notification[index].sprite = Sprite ();
3538++ message_notification[index].sprite.SetImage (message_notification[index].image);
3539++ message_notification[index].sprite.SetX (message_notification[index].x);
3540++ message_notification[index].sprite.SetY (message_notification[index].y);
3541++ message_notification[index].sprite.SetZ (message_notification[index].z);
3542++
3543++}
3544++
3545++fun show_message (index) {
3546++ if (global.message_notification[index].sprite) global.message_notification[index].sprite.SetOpacity(1);
3547++}
3548++
3549++fun hide_message (index) {
3550++ if (global.message_notification[index].sprite) global.message_notification[index].sprite.SetOpacity(0);
3551++}
3552++
3553++
3554++
3555++
3556++# the callback function is called when new message should be displayed.
3557++# First arg is message to display.
3558++fun message_callback (message)
3559++{
3560++ # Debug("Message callback");
3561++ is_fake = 0;
3562++ if (!message || (message == "")) is_fake = 1;
3563++
3564++ local.substring = "keys:";
3565++
3566++ # Look for the "keys:" prefix
3567++ local.keys = StringString(message, local.substring);
3568++
3569++ local.is_action_line = (keys != NULL);
3570++ #Debug("keys " + local.keys + " substring length = " + StringLength(local.substring));
3571++
3572++ # Get the message without the "keys:" prefix
3573++ if (keys != NULL)
3574++ message = StringCopy (message, keys + StringLength(local.substring), NULL);
3575++
3576++ local.label.is_fake = is_fake;
3577++ label = get_message_label(message, is_fake, is_action_line);
3578++ label.z = 10000;
3579++
3580++ setup_message (message, label.x, label.y, label.z, is_action_line);
3581++ if (prompt_active && local.is_action_line)
3582++ hide_message (is_action_line);
3583++ else
3584++ show_message (is_action_line);
3585++
3586++}
3587++
3588++
3589++#-----------------------------------------Display Password stuff -----------------------
3590++#
3591++
3592++fun password_dialogue_setup (message_label) {
3593++ # Debug("Password dialog setup");
3594++
3595++ local.entry;
3596++ local.bullet_image;
3597++ bullet_image = LoadScaleImage (progress_dot_off_filename);
3598++ entry.image = LoadScaleImage (password_field_filename);
3599++
3600++ # Hide the normal labels
3601++ prompt_active = 1;
3602++ if (message_notification[1].sprite) hide_message (1);
3603++
3604++ # Set the prompt label
3605++ label = get_message_label(message_label, 0, 1);
3606++ label.z = 10000;
3607++
3608++ setup_message (message_label, label.x, label.y, label.z, 2);
3609++ show_message (2);
3610++
3611++ # Set up the text entry which contains the bullets
3612++ entry.sprite = Sprite ();
3613++ entry.sprite.SetImage (entry.image);
3614++
3615++ # Centre the box horizontally
3616++ entry.x = Window.GetX () + Window.GetWidth () / 2 - entry.image.GetWidth () / 2;
3617++
3618++ # Put the entry below the second label.
3619++ entry.y = message_notification[2].y + label.height;
3620++
3621++ #Debug ("entry x = " + entry.x + ", y = " + entry.y);
3622++ entry.z = 10000;
3623++ entry.sprite.SetX (entry.x);
3624++ entry.sprite.SetY (entry.y);
3625++ entry.sprite.SetZ (entry.z);
3626++
3627++ global.password_dialogue = local;
3628++}
3629++
3630++fun password_dialogue_opacity (opacity) {
3631++ # Debug("Password dialog opacity");
3632++ global.password_dialogue.opacity = opacity;
3633++ local = global.password_dialogue;
3634++
3635++ # You can make the box translucent with a float
3636++ # entry.sprite.SetOpacity (0.3);
3637++ entry.sprite.SetOpacity (opacity);
3638++ label.sprite.SetOpacity (opacity);
3639++
3640++ if (bullets) {
3641++ for (index = 0; bullets[index]; index++) {
3642++ bullets[index].sprite.SetOpacity (opacity);
3643++ }
3644++ }
3645++}
3646++
3647++
3648++# The callback function is called when the display should display a password dialogue.
3649++# First arg is prompt string, the second is the number of bullets.
3650++fun display_password_callback (prompt, bullets) {
3651++ # Debug("Password dialog setup");
3652++
3653++ global.status = "password";
3654++ if (!global.password_dialogue) password_dialogue_setup(prompt);
3655++ password_dialogue_opacity (1);
3656++ bullet_width = password_dialogue.bullet_image.GetWidth();
3657++ bullet_y = password_dialogue.entry.y +
3658++ password_dialogue.entry.image.GetHeight () / 2 -
3659++ password_dialogue.bullet_image.GetHeight () / 2;
3660++ margin = bullet_width;
3661++ spaces = Math.Int( (password_dialogue.entry.image.GetWidth () - (margin * 2) ) / ( 2 * bullet_width / 3 ) );
3662++ #Debug ("spaces = " + spaces + ", bullets = " + bullets);
3663++ bullets_area.width = margin + spaces * ( 2 * bullet_width / 3);
3664++ bullets_area.x = Window.GetX () + Window.GetWidth () / 2 - bullets_area.width / 2;
3665++ #DebugBottom ("pwd_entry x = " + password_dialogue.entry.x + ", bullets_area.x = " + bullets_area.x + ", bullets_area.width = " + bullets_area.width);
3666++ if (bullets > spaces)
3667++ bullets = spaces;
3668++ for (index = 0; password_dialogue.bullets[index] || index < spaces ; index++){
3669++ if (!password_dialogue.bullets[index]) {
3670++ password_dialogue.bullets[index].sprite = Sprite ();
3671++ password_dialogue.bullets[index].sprite.SetImage (password_dialogue.bullet_image);
3672++ password_dialogue.bullets[index].x = bullets_area.x + # password_dialogue.entry.x + margin +
3673++ index * ( 2 * bullet_width / 3 ) ;
3674++ password_dialogue.bullets[index].sprite.SetX (password_dialogue.bullets[index].x);
3675++ password_dialogue.bullets[index].y = bullet_y;
3676++ password_dialogue.bullets[index].sprite.SetY (password_dialogue.bullets[index].y);
3677++ password_dialogue.bullets[index].z = password_dialogue.entry.z + 100 - index;
3678++ password_dialogue.bullets[index].sprite.SetZ (password_dialogue.bullets[index].z);
3679++ }
3680++
3681++ password_dialogue.bullets[index].sprite.SetOpacity (0);
3682++
3683++ if (index < bullets ) {
3684++ password_dialogue.bullets[index].sprite.SetOpacity (1);
3685++ }
3686++ }
3687++}
3688++
3689++Plymouth.SetDisplayPasswordFunction (display_password_callback);
3690++
3691++Plymouth.SetMessageFunction (message_callback);
3692++
3693++Plymouth.SetBootProgressFunction (animate_progress_indicator);
3694++
3695++# Plymouth.SetBootProgressFunction: the callback function is called with two numbers, the progress (between 0 and 1) and the time spent booting so far
3696++# Plymouth.SetRootMountedFunction: the callback function is called when a new root is mounted
3697++# Plymouth.SetKeyboardInputFunction: the callback function is called with a string containing a new character entered on the keyboard
3698++
3699++#----------------------------------------- FSCK Counter --------------------------------
3700++
3701++# Initialise the counter
3702++fun init_fsck_count () {
3703++ # The number of fsck checks in this cycle
3704++ global.counter.total = 0;
3705++ # The number of fsck checks already performed + the current one
3706++ global.counter.current = 1;
3707++ # The previous fsck
3708++ global.counter.last = 0;
3709++}
3710++
3711++# Increase the total counter
3712++fun increase_fsck_count () {
3713++ global.counter.total++;
3714++}
3715++
3716++fun increase_current_fsck_count () {
3717++ global.counter.last = global.counter.current++;
3718++}
3719++
3720++# Clear the counter
3721++fun clear_fsck_count () {
3722++ global.counter = NULL;
3723++ init_fsck_count ();
3724++}
3725++
3726++#----------------------------------------- Progress Label ------------------------------
3727++
3728++
3729++# Change the opacity level of a progress label
3730++#
3731++# opacity = 1 -> show
3732++# opacity = 0 -> hide
3733++# opacity = 0.3 (or any other float) -> translucent
3734++#
3735++fun set_progress_label_opacity (opacity) {
3736++ # the label
3737++ progress_label.sprite.SetOpacity (opacity);
3738++
3739++ # Make the slot available again when hiding the bar
3740++ # So that another bar can take its place
3741++ if (opacity == 0) {
3742++ progress_label.is_available = 1;
3743++ progress_label.device = "";
3744++ }
3745++}
3746++
3747++# Set up a new Progress Bar
3748++#
3749++# TODO: Make it possible to reuse (rather than recreate) a bar
3750++# if .is_available = 1. Ideally this would just reset the
3751++# label, the associated
3752++# device and the image size of the sprite.
3753++
3754++fun init_progress_label (device, status_string) {
3755++ # Make the slot unavailable
3756++ global.progress_label.is_available = 0;
3757++ progress_label.progress = 0;
3758++ progress_label.device = device;
3759++ progress_label.status_string = status_string;
3760++}
3761++
3762++# See if the progress label is keeping track of the fsck
3763++# of "device"
3764++#
3765++fun device_has_progress_label (device) {
3766++ #DebugBottom ("label device = " + progress_label.device + " checking device " + device);
3767++ return (progress_label.device == device);
3768++}
3769++
3770++# Update the Progress bar which corresponds to index
3771++#
3772++fun update_progress_label (progress) {
3773++ # If progress is NULL then we just refresh the label.
3774++ # This happens when only counter.total has changed.
3775++ if (progress != NULL) {
3776++ progress_label.progress = progress;
3777++
3778++ #Debug("device " + progress_label.device + " progress " + progress);
3779++
3780++ # If progress >= 100% hide the label and make it available again
3781++ if (progress >= 100) {
3782++ set_progress_label_opacity (0);
3783++
3784++ # See if we any other fsck check is complete
3785++ # and, if so, hide the progress bars and the labels
3786++ on_fsck_completed ();
3787++
3788++ return 0;
3789++ }
3790++ }
3791++ # Update progress label here
3792++ #
3793++ # FIXME: the queue logic from this theme should really be moved into mountall
3794++ # instead of using string replacement to deal with localised strings.
3795++ label = StringReplace (progress_label.status_string[0], "%1$d", global.counter.current);
3796++ label = StringReplace (label, "%2$d", global.counter.total);
3797++ label = StringReplace (label, "%3$d", progress_label.progress);
3798++ label = StringReplace (label, "%%", "%");
3799++
3800++ progress_label = get_fsck_label (label, 0);
3801++ #progress_label.progress = progress;
3802++
3803++ progress_label.sprite = Sprite (progress_label.image);
3804++
3805++ # Set up the bar
3806++ progress_label.sprite.SetPosition(progress_label.x, progress_label.y, 1);
3807++
3808++ set_progress_label_opacity (1);
3809++
3810++}
3811++
3812++# Refresh the label so as to update counters
3813++fun refresh_progress_label () {
3814++ update_progress_label (NULL);
3815++}
3816++
3817++#----------------------------------------- FSCK Queue ----------------------------------
3818++
3819++# Initialise the fsck queue
3820++fun init_queue () {
3821++ global.fsck_queue[0].device;
3822++ global.fsck_queue[0].progress;
3823++ global.fsck_queue.counter = 0;
3824++ global.fsck_queue.biggest_item = 0;
3825++}
3826++
3827++fun clear_queue () {
3828++ global.fsck_queue = NULL;
3829++ init_queue ();
3830++}
3831++
3832++# Return either the device index in the queue or -1
3833++fun queue_look_up_by_device (device) {
3834++ for (i=0; i <= fsck_queue.biggest_item; i++) {
3835++ if ((fsck_queue[i]) && (fsck_queue[i].device == device))
3836++ return i;
3837++ }
3838++ return -1;
3839++}
3840++
3841++# Keep track of an fsck process in the queue
3842++fun add_fsck_to_queue (device, progress) {
3843++ # Look for an empty slot in the queue
3844++ for (i=0; global.fsck_queue[i].device; i++) {
3845++ continue;
3846++ }
3847++ local.index = i;
3848++
3849++ # Set device and progress
3850++ global.fsck_queue[local.index].device = device;
3851++ global.fsck_queue[local.index].progress = progress;
3852++
3853++ # Increase the queue counter
3854++ global.fsck_queue.counter++;
3855++
3856++ # Update the max index of the array for iterations
3857++ if (local.index > global.fsck_queue.biggest_item)
3858++ global.fsck_queue.biggest_item = local.index;
3859++
3860++ #DebugMedium ("Adding " + device + " at " + local.index);
3861++}
3862++
3863++fun is_queue_empty () {
3864++ return (fsck_queue.counter == 0);
3865++}
3866++
3867++fun is_progress_label_available () {
3868++ return (progress_label.is_available == 1);
3869++}
3870++
3871++
3872++# This should cover the case in which the fsck checks in
3873++# the queue are completed before the ones showed in the
3874++# progress label
3875++fun on_queued_fsck_completed () {
3876++ if (!is_queue_empty ())
3877++ return;
3878++
3879++ # Hide the extra label, if any
3880++ #if (progress_bar.extra_label.sprite)
3881++ # progress_bar.extra_label.sprite.SetOpacity(0);
3882++}
3883++
3884++fun remove_fsck_from_queue (index) {
3885++ # Free memory which was previously allocated for
3886++ # device and progress
3887++ global.fsck_queue[index].device = NULL;
3888++ global.fsck_queue[index].progress = NULL;
3889++
3890++ # Decrease the queue counter
3891++ global.fsck_queue.counter--;
3892++
3893++ # See if there are other processes in the queue
3894++ # if not, clear the extra_label
3895++ on_queued_fsck_completed ();
3896++}
3897++
3898++fun on_fsck_completed () {
3899++ # We have moved on to tracking the next fsck
3900++ increase_current_fsck_count ();
3901++
3902++ if (!is_progress_label_available ())
3903++ return;
3904++
3905++ if (!is_queue_empty ())
3906++ return;
3907++
3908++ # Hide the progress label
3909++ if (progress_label.sprite)
3910++ progress_label.sprite.SetOpacity (0);
3911++
3912++ # Clear the queue
3913++ clear_queue ();
3914++
3915++ # Clear the fsck counter
3916++ clear_fsck_count ();
3917++}
3918++
3919++# Update an fsck process that we keep track of in the queue
3920++fun update_progress_in_queue (index, device, progress) {
3921++ # If the fsck is complete, remove it from the queue
3922++ if (progress >= 100) {
3923++ remove_fsck_from_queue (index);
3924++ on_queued_fsck_completed ();
3925++ return;
3926++ }
3927++
3928++ global.fsck_queue[index].device = device;
3929++ global.fsck_queue[index].progress = progress;
3930++
3931++}
3932++
3933++# TODO: Move it to some function
3934++# Create an empty queue
3935++#init_queue ();
3936++
3937++
3938++#----------------------------------------- FSCK Functions ------------------------------
3939++
3940++
3941++# Either add a new bar for fsck checks or update an existing bar
3942++#
3943++# NOTE: no more than "progress_bar.max_number" bars are allowed
3944++#
3945++fun fsck_check (device, progress, status_string) {
3946++
3947++ # The 1st time this will take place
3948++ if (!global.progress_label) {
3949++ # Increase the fsck counter
3950++ increase_fsck_count ();
3951++
3952++ # Set up a new label for the check
3953++ init_progress_label (device, status_string);
3954++ update_progress_label (progress);
3955++
3956++ return;
3957++ }
3958++
3959++
3960++ if (device_has_progress_label (device)) {
3961++ # Update the progress of the existing label
3962++ update_progress_label (progress);
3963++ }
3964++ else {
3965++ # See if there's already a slot in the queue for the device
3966++ local.queue_device_index = queue_look_up_by_device(device);
3967++
3968++ # See if the progress_label is available
3969++ if (progress_label.is_available) {
3970++
3971++# local.my_string = "available index " + local.available_index + " progress_bar counter is " + progress_bar.counter;
3972++# Debug(local.my_string);
3973++
3974++
3975++ # If the fsck check for the device was in the queue, then
3976++ # remove it from the queue
3977++ if (local.queue_device_index >= 0) {
3978++ remove_fsck_from_queue (index);
3979++ }
3980++ else {
3981++ # Increase the fsck counter
3982++ increase_fsck_count ();
3983++ }
3984++
3985++# local.my_string += local.message;
3986++ #Debug("setting new label for device " + device + " progress " + progress);
3987++
3988++ # Set up a new label for the check
3989++ init_progress_label (device, status_string);
3990++ update_progress_label (progress);
3991++
3992++ }
3993++ # If the progress_label is not available
3994++ else {
3995++
3996++ # If the fsck check for the device is already in the queue
3997++ # just update its progress in the queue
3998++ if (local.queue_device_index >= 0) {
3999++ #DebugMedium("Updating queue at " + local.queue_device_index + " for device " + device);
4000++ update_progress_in_queue (local.queue_device_index, device, progress);
4001++ }
4002++ # Otherwise add the check to the queue
4003++ else {
4004++ #DebugMedium("Adding device " + device + " to queue at " + local.queue_device_index);
4005++ add_fsck_to_queue (device, progress);
4006++
4007++ # Increase the fsck counter
4008++ increase_fsck_count ();
4009++
4010++ refresh_progress_label ();
4011++ }
4012++
4013++ }
4014++ }
4015++
4016++# if (!is_queue_empty ()) {
4017++# DebugBottom("Extra label for "+ device);
4018++ #}
4019++# else {
4020++# DebugBottom("No extra label for " + device + ". 1st Device in the queue "+ fsck_queue[0].device + " counter = " + global.fsck_queue.counter);
4021++# }
4022++}
4023++
4024++
4025++#-----------------------------------------Update Status stuff --------------------------
4026++#
4027++# The update_status_callback is what we can use to pass plymouth whatever we want so
4028++# as to make use of features which are available only in this program (as opposed to
4029++# being available for any theme for the script plugin).
4030++#
4031++# Example:
4032++#
4033++# Thanks to the current implementation, some scripts can call "plymouth --update=fsck:sda1:40"
4034++# and this program will know that 1) we're performing and fsck check, 2) we're checking sda1,
4035++# 3) the program should set the label progress to 40%
4036++#
4037++# Other features can be easily added by parsing the string that we pass plymouth with "--update"
4038++#
4039++fun update_status_callback (status) {
4040++# Debug(status);
4041++ if (!status) return;
4042++
4043++ string_it = 0;
4044++ update_strings[string_it] = "";
4045++
4046++ for (i=0; (String(status).CharAt(i) != ""); i++) {
4047++ local.temp_char = String(status).CharAt(i);
4048++ if (temp_char != ":")
4049++ update_strings[string_it] += temp_char;
4050++ else
4051++ update_strings[++string_it] = "";
4052++ }
4053++
4054++# my_string = update_strings[0] + " " + update_strings[1] + " " + update_strings[2];
4055++# Debug(my_string);
4056++ # Let's assume that we're dealing with these strings fsck:sda1:40
4057++ if ((string_it >= 2) && (update_strings[0] == "fsck")) {
4058++
4059++ device = update_strings[1];
4060++ progress = update_strings[2];
4061++ status_string[0] = update_strings[3]; # "Checking disk %1$d of %2$d (%3$d %% complete)"
4062++ if (!status_string[0])
4063++ status_string[0] = "Checking disk %1$d of %2$d (%3$d %% complete)";
4064++
4065++ if ((device != "") && (progress != "")) {
4066++ progress = StringToInteger (progress);
4067++
4068++ # Make sure that the fsck_queue is initialised
4069++ if (!global.fsck_queue)
4070++ init_queue ();
4071++
4072++ # Make sure that the fsck counter is initialised
4073++ if (!global.counter)
4074++ init_fsck_count ();
4075++
4076++# if (!global.progress_bar.extra_label.sprite)
4077++# create_extra_fsck_label ();
4078++
4079++ # Keep track of the fsck check
4080++ fsck_check (device, progress, status_string);
4081++ }
4082++
4083++ }
4084++
4085++}
4086++Plymouth.SetUpdateStatusFunction (update_status_callback);
4087++
4088++#-----------------------------------------Display Question stuff -----------------------
4089++
4090++fun question_dialogue_setup (message_label, text_image) {
4091++ #Debug("Question dialog setup");
4092++
4093++ local.field;
4094++ local.content;
4095++ local.margin;
4096++
4097++ field.image = LoadScaleImage (question_field_filename);
4098++ content = Sprite ();
4099++ bullet_image = LoadScaleImage (progress_dot_off_filename);
4100++ margin = bullet_image.GetWidth() / 2;
4101++
4102++ # Hide the normal labels
4103++ prompt_active = 1;
4104++ if (message_notification[1].sprite) hide_message (1);
4105++
4106++ # Set the prompt label
4107++ label = get_message_label(message_label, 0, 1);
4108++ label.z = 10000;
4109++
4110++ setup_message (message_label, label.x, label.y, label.z, 2);
4111++ show_message (2);
4112++
4113++ # Set up the text field which contains the contents
4114++ field.sprite = Sprite ();
4115++ field.sprite.SetImage (field.image);
4116++
4117++ # Centre the box horizontally
4118++ field.x = Window.GetX () + Window.GetWidth () / 2 - field.image.GetWidth () / 2;
4119++ content_x = field.x + margin;
4120++
4121++ # Put the field below the second label.
4122++ field.y = message_notification[2].y + label.height;
4123++ content_y = field.y + field.image.GetHeight () / 2 - text_image.GetHeight () / 2;
4124++
4125++ #Debug ("field x = " + field.x + ", y = " + field.y);
4126++ field.z = 10000;
4127++ field.sprite.SetX (field.x);
4128++ field.sprite.SetY (field.y);
4129++ field.sprite.SetZ (field.z);
4130++
4131++ #Debug ("content_x = " + content_x + " content_y = " + content_y);
4132++ content_z = field.z + 1;
4133++ content.SetPosition (content_x, content_y, content_z);
4134++
4135++ global.question_dialogue = local;
4136++}
4137++
4138++# The callback function is called when the display should display a question dialogue.
4139++# First arg is prompt string, the second is the field contents.
4140++fun display_question_callback (prompt, contents) {
4141++ global.status = "question";
4142++ #Debug ("Reply: " + contents);
4143++
4144++ textImage = ImageToText(contents);
4145++ if (!global.question_dialogue) {
4146++ question_dialogue_setup(prompt, textImage);
4147++ }
4148++
4149++ margin = global.question_dialogue.margin;
4150++ fieldWidth = global.question_dialogue.field.image.GetWidth ();
4151++ for (i = 0; ( (textImage.GetWidth () + 2 * margin ) > fieldWidth ); i++) {
4152++ textImage = ImageToText(StringCopy (contents, i, StringLength (contents)));
4153++ }
4154++
4155++ global.question_dialogue.content.SetImage (textImage);
4156++}
4157++
4158++
4159++Plymouth.SetDisplayQuestionFunction (display_question_callback);
4160++
4161++#-----------------------------------------Refresh stuff --------------------------------
4162++#
4163++# Calling Plymouth.SetRefreshFunction with a function will set that function to be
4164++# called up to 50 times every second, e.g.
4165++#
4166++# NOTE: if a refresh function is not set, Plymouth doesn't seem to be able to update
4167++# the screen correctly
4168++#
4169++fun refresh_callback ()
4170++{
4171++ draw_logo ();
4172++}
4173++Plymouth.SetRefreshFunction (refresh_callback);
4174++
4175++
4176++#-----------------------------------------Display Normal stuff -----------------------
4177++#
4178++# The callback function is called when the display should return to normal
4179++fun display_normal_callback ()
4180++{
4181++ global.status = "normal";
4182++ if (global.password_dialogue) {
4183++ password_dialogue_opacity (0);
4184++ global.password_dialogue = NULL;
4185++ if (message_notification[2].sprite) hide_message(2);
4186++ prompt_active = 0;
4187++ }
4188++ if (global.question_dialogue) {
4189++ question_dialogue_opacity (0);
4190++ global.question_dialogue = NULL;
4191++ if (message_notification[2].sprite) hide_message(2);
4192++ prompt_active = 0;
4193++ }
4194++
4195++ if (message_notification[1].sprite) show_message (1);
4196++
4197++}
4198++
4199++Plymouth.SetDisplayNormalFunction (display_normal_callback);
4200++
4201++
4202++#----------------------------------------- Quit --------------------------------
4203++
4204++# TODO: Maybe we should also hide any other dialog
4205++# Show the logo and make the progress indicator look full when on exit
4206++fun quit_callback ()
4207++{
4208++ logo.sprite.SetOpacity (1);
4209++ switch_on_bullets ();
4210++}
4211++
4212++Plymouth.SetQuitFunction(quit_callback);
4213
4214=== added file 'debian/patches/use-upstart-private-socket.patch'
4215--- debian/patches/use-upstart-private-socket.patch 1970-01-01 00:00:00 +0000
4216+++ debian/patches/use-upstart-private-socket.patch 2014-03-14 10:43:52 +0000
4217@@ -0,0 +1,198 @@
4218+Description: use private upstart socket to start earlier
4219+Author: Dimitri John Ledkov <xnox@ubuntu.com>
4220+
4221+--- a/src/upstart-bridge/ply-upstart-monitor.c
4222++++ b/src/upstart-bridge/ply-upstart-monitor.c
4223+@@ -46,7 +46,6 @@
4224+ struct _ply_upstart_monitor
4225+ {
4226+ DBusConnection *connection;
4227+- char *owner;
4228+ ply_event_loop_t *loop;
4229+ ply_hashtable_t *jobs;
4230+ ply_hashtable_t *all_instances;
4231+@@ -74,7 +73,8 @@
4232+ uint32_t call_failed : 1;
4233+ } ply_upstart_monitor_instance_t;
4234+
4235+-#define UPSTART_SERVICE "com.ubuntu.Upstart"
4236++#define UPSTART_SERVICE NULL
4237++#define DBUS_ADDRESS_UPSTART "unix:abstract=/com/ubuntu/upstart"
4238+ #define UPSTART_PATH "/com/ubuntu/Upstart"
4239+ #define UPSTART_INTERFACE_0_6 "com.ubuntu.Upstart0_6"
4240+ #define UPSTART_INTERFACE_0_6_JOB "com.ubuntu.Upstart0_6.Job"
4241+@@ -579,82 +579,6 @@
4242+ dbus_message_unref (reply);
4243+ }
4244+
4245+-static void
4246+-on_get_name_owner_finished (DBusPendingCall *call,
4247+- ply_upstart_monitor_t *monitor)
4248+-{
4249+- DBusMessage *reply, *message;
4250+- DBusError error;
4251+- const char *owner;
4252+-
4253+- assert (call != NULL);
4254+- assert (monitor != NULL);
4255+-
4256+- reply = dbus_pending_call_steal_reply (call);
4257+- if (reply == NULL)
4258+- return;
4259+- if (dbus_message_get_type (reply) != DBUS_MESSAGE_TYPE_METHOD_RETURN)
4260+- goto out;
4261+-
4262+- dbus_error_init (&error);
4263+- dbus_message_get_args (reply, &error,
4264+- DBUS_TYPE_STRING, &owner,
4265+- DBUS_TYPE_INVALID);
4266+- if (dbus_error_is_set (&error))
4267+- goto out;
4268+- dbus_error_free (&error);
4269+-
4270+- ply_trace ("owner = '%s'", owner);
4271+-
4272+- free (monitor->owner);
4273+- monitor->owner = strdup (owner);
4274+-
4275+- ply_trace ("calling GetAllJobs");
4276+- message = dbus_message_new_method_call (UPSTART_SERVICE, UPSTART_PATH,
4277+- UPSTART_INTERFACE_0_6,
4278+- "GetAllJobs");
4279+- dbus_connection_send_with_reply (monitor->connection, message, &call, -1);
4280+- dbus_message_unref (message);
4281+- if (call != NULL)
4282+- dbus_pending_call_set_notify (call,
4283+- (DBusPendingCallNotifyFunction)
4284+- on_get_all_jobs_finished,
4285+- monitor, NULL);
4286+-
4287+-out:
4288+- dbus_message_unref (reply);
4289+-}
4290+-
4291+-static DBusHandlerResult
4292+-name_owner_changed_handler (DBusConnection *connection,
4293+- DBusMessage *message,
4294+- ply_upstart_monitor_t *monitor)
4295+-{
4296+- DBusError error;
4297+- const char *name, *old_owner, *new_owner;
4298+-
4299+- assert (connection != NULL);
4300+- assert (message != NULL);
4301+- assert (monitor != NULL);
4302+-
4303+- dbus_error_init (&error);
4304+- if (dbus_message_get_args (message, &error,
4305+- DBUS_TYPE_STRING, &name,
4306+- DBUS_TYPE_STRING, &old_owner,
4307+- DBUS_TYPE_STRING, &new_owner,
4308+- DBUS_TYPE_INVALID) &&
4309+- strcmp (name, UPSTART_SERVICE) == 0)
4310+- {
4311+- if (new_owner)
4312+- ply_trace ("owner changed from '%s' to '%s'", old_owner, new_owner);
4313+- else
4314+- ply_trace ("owner left bus");
4315+- free (monitor->owner);
4316+- monitor->owner = new_owner ? strdup (new_owner) : NULL;
4317+- }
4318+-
4319+- return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; /* let other handlers try */
4320+-}
4321+
4322+ static DBusHandlerResult
4323+ job_added_handler (DBusConnection *connection,
4324+@@ -856,12 +780,6 @@
4325+ if (path == NULL)
4326+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
4327+
4328+- if (dbus_message_is_signal (message, DBUS_INTERFACE_DBUS,
4329+- "NameOwnerChanged") &&
4330+- dbus_message_has_path (message, DBUS_PATH_DBUS) &&
4331+- dbus_message_has_sender (message, DBUS_SERVICE_DBUS))
4332+- return name_owner_changed_handler (connection, message, monitor);
4333+-
4334+ if (dbus_message_is_signal (message, UPSTART_INTERFACE_0_6,
4335+ "JobAdded"))
4336+ return job_added_handler (connection, message, monitor);
4337+@@ -899,9 +817,7 @@
4338+ DBusError error;
4339+ DBusConnection *connection;
4340+ ply_upstart_monitor_t *monitor;
4341+- char *rule;
4342+ DBusMessage *message;
4343+- const char *monitor_service = UPSTART_SERVICE;
4344+ DBusPendingCall *call;
4345+
4346+ dbus_error_init (&error);
4347+@@ -909,7 +825,7 @@
4348+ /* Get a connection to the system bus and set it up to listen for messages
4349+ * from Upstart.
4350+ */
4351+- connection = dbus_bus_get (DBUS_BUS_SYSTEM, &error);
4352++ connection = dbus_connection_open (DBUS_ADDRESS_UPSTART, &error);
4353+ if (connection == NULL)
4354+ {
4355+ ply_error ("unable to connect to system bus: %s", error.message);
4356+@@ -938,52 +854,17 @@
4357+ return NULL;
4358+ }
4359+
4360+- asprintf (&rule, "type='%s',sender='%s',path='%s',"
4361+- "interface='%s',member='%s',arg0='%s'",
4362+- "signal", DBUS_SERVICE_DBUS, DBUS_PATH_DBUS,
4363+- DBUS_INTERFACE_DBUS, "NameOwnerChanged", UPSTART_SERVICE);
4364+- dbus_bus_add_match (connection, rule, &error);
4365+- free (rule);
4366+- if (dbus_error_is_set (&error))
4367+- {
4368+- ply_error ("unable to add match rule to system bus connection: %s",
4369+- error.message);
4370+- ply_upstart_monitor_free (monitor);
4371+- dbus_error_free (&error);
4372+- return NULL;
4373+- }
4374+-
4375+- asprintf (&rule, "type='%s',sender='%s'", "signal", UPSTART_SERVICE);
4376+- dbus_bus_add_match (connection, rule, &error);
4377+- free (rule);
4378+- if (dbus_error_is_set (&error))
4379+- {
4380+- ply_error ("unable to add match rule to system bus connection: %s",
4381+- error.message);
4382+- ply_upstart_monitor_free (monitor);
4383+- dbus_error_free (&error);
4384+- return NULL;
4385+- }
4386+-
4387+- /* Start the state machine going: find out the current owner of the
4388+- * well-known Upstart name.
4389+- * Ignore errors: the worst case is that we don't get any messages back
4390+- * and our state machine does nothing.
4391+- */
4392+- ply_trace ("calling GetNameOwner");
4393+- message = dbus_message_new_method_call (DBUS_SERVICE_DBUS, DBUS_PATH_DBUS,
4394+- DBUS_INTERFACE_DBUS, "GetNameOwner");
4395+- dbus_message_append_args (message,
4396+- DBUS_TYPE_STRING, &monitor_service,
4397+- DBUS_TYPE_INVALID);
4398+- dbus_connection_send_with_reply (connection, message, &call, -1);
4399++ ply_trace ("calling GetAllJobs");
4400++ message = dbus_message_new_method_call (UPSTART_SERVICE, UPSTART_PATH,
4401++ UPSTART_INTERFACE_0_6,
4402++ "GetAllJobs");
4403++ dbus_connection_send_with_reply (monitor->connection, message, &call, -1);
4404+ dbus_message_unref (message);
4405+ if (call != NULL)
4406+ dbus_pending_call_set_notify (call,
4407+ (DBusPendingCallNotifyFunction)
4408+- on_get_name_owner_finished,
4409+- monitor,
4410+- NULL);
4411++ on_get_all_jobs_finished,
4412++ monitor, NULL);
4413+
4414+ if (loop != NULL)
4415+ ply_upstart_monitor_connect_to_event_loop (monitor, loop);
4416
4417=== modified file 'debian/plymouth-theme-ubuntu-logo.postinst'
4418--- debian/plymouth-theme-ubuntu-logo.postinst 2011-04-15 13:35:04 +0000
4419+++ debian/plymouth-theme-ubuntu-logo.postinst 2014-03-14 10:43:52 +0000
4420@@ -24,6 +24,12 @@
4421 --slave /lib/plymouth/themes/default.grub default.plymouth.grub \
4422 /lib/plymouth/themes/ubuntu-logo/ubuntu-logo.grub
4423
4424+ update-alternatives \
4425+ --install /lib/plymouth/themes/default.plymouth default.plymouth \
4426+ /lib/plymouth/themes/ubuntu-logo/ubuntu-logo-scale-2.plymouth 99 \
4427+ --slave /lib/plymouth/themes/default.grub default.plymouth.grub \
4428+ /lib/plymouth/themes/ubuntu-logo/ubuntu-logo.grub
4429+
4430 if which update-initramfs >/dev/null 2>&1
4431 then
4432 update-initramfs -u
4433
4434=== modified file 'debian/plymouth-theme-ubuntu-logo.prerm'
4435--- debian/plymouth-theme-ubuntu-logo.prerm 2011-02-09 20:41:53 +0000
4436+++ debian/plymouth-theme-ubuntu-logo.prerm 2014-03-14 10:43:52 +0000
4437@@ -5,6 +5,8 @@
4438 if [ "x$1" = xremove ]; then
4439 update-alternatives \
4440 --remove default.plymouth /lib/plymouth/themes/ubuntu-logo/ubuntu-logo.plymouth
4441+ update-alternatives \
4442+ --remove default.plymouth /lib/plymouth/themes/ubuntu-logo/ubuntu-logo-scale-2.plymouth
4443 fi
4444
4445 #DEBHELPER#
4446
4447=== modified file 'debian/plymouth.plymouth-upstart-bridge.upstart'
4448--- debian/plymouth.plymouth-upstart-bridge.upstart 2012-09-07 18:03:39 +0000
4449+++ debian/plymouth.plymouth-upstart-bridge.upstart 2014-03-14 10:43:52 +0000
4450@@ -5,9 +5,12 @@
4451
4452 description "bridge from Upstart state changes to Plymouth"
4453
4454-start on (started dbus
4455+respawn
4456+
4457+start on (startup
4458 or runlevel [06])
4459-stop on stopping plymouth
4460+stop on (stopping plymouth
4461+ or stopping plymouth-shutdown)
4462
4463 console output
4464
4465
4466=== modified file 'src/upstart-bridge/ply-upstart-monitor.c'
4467--- src/upstart-bridge/ply-upstart-monitor.c 2011-03-12 22:54:53 +0000
4468+++ src/upstart-bridge/ply-upstart-monitor.c 2014-03-14 10:43:52 +0000
4469@@ -46,7 +46,6 @@
4470 struct _ply_upstart_monitor
4471 {
4472 DBusConnection *connection;
4473- char *owner;
4474 ply_event_loop_t *loop;
4475 ply_hashtable_t *jobs;
4476 ply_hashtable_t *all_instances;
4477@@ -74,7 +73,8 @@
4478 uint32_t call_failed : 1;
4479 } ply_upstart_monitor_instance_t;
4480
4481-#define UPSTART_SERVICE "com.ubuntu.Upstart"
4482+#define UPSTART_SERVICE NULL
4483+#define DBUS_ADDRESS_UPSTART "unix:abstract=/com/ubuntu/upstart"
4484 #define UPSTART_PATH "/com/ubuntu/Upstart"
4485 #define UPSTART_INTERFACE_0_6 "com.ubuntu.Upstart0_6"
4486 #define UPSTART_INTERFACE_0_6_JOB "com.ubuntu.Upstart0_6.Job"
4487@@ -273,7 +273,7 @@
4488 DBUS_TYPE_STRING)
4489 goto next_item;
4490 dbus_message_iter_get_basic (&variant_iter, &description);
4491- if (description != NULL)
4492+ if (description != NULL && description[0])
4493 {
4494 ply_trace ("description = '%s'", description);
4495 job->properties.description = strdup (description);
4496@@ -579,82 +579,6 @@
4497 dbus_message_unref (reply);
4498 }
4499
4500-static void
4501-on_get_name_owner_finished (DBusPendingCall *call,
4502- ply_upstart_monitor_t *monitor)
4503-{
4504- DBusMessage *reply, *message;
4505- DBusError error;
4506- const char *owner;
4507-
4508- assert (call != NULL);
4509- assert (monitor != NULL);
4510-
4511- reply = dbus_pending_call_steal_reply (call);
4512- if (reply == NULL)
4513- return;
4514- if (dbus_message_get_type (reply) != DBUS_MESSAGE_TYPE_METHOD_RETURN)
4515- goto out;
4516-
4517- dbus_error_init (&error);
4518- dbus_message_get_args (reply, &error,
4519- DBUS_TYPE_STRING, &owner,
4520- DBUS_TYPE_INVALID);
4521- if (dbus_error_is_set (&error))
4522- goto out;
4523- dbus_error_free (&error);
4524-
4525- ply_trace ("owner = '%s'", owner);
4526-
4527- free (monitor->owner);
4528- monitor->owner = strdup (owner);
4529-
4530- ply_trace ("calling GetAllJobs");
4531- message = dbus_message_new_method_call (UPSTART_SERVICE, UPSTART_PATH,
4532- UPSTART_INTERFACE_0_6,
4533- "GetAllJobs");
4534- dbus_connection_send_with_reply (monitor->connection, message, &call, -1);
4535- dbus_message_unref (message);
4536- if (call != NULL)
4537- dbus_pending_call_set_notify (call,
4538- (DBusPendingCallNotifyFunction)
4539- on_get_all_jobs_finished,
4540- monitor, NULL);
4541-
4542-out:
4543- dbus_message_unref (reply);
4544-}
4545-
4546-static DBusHandlerResult
4547-name_owner_changed_handler (DBusConnection *connection,
4548- DBusMessage *message,
4549- ply_upstart_monitor_t *monitor)
4550-{
4551- DBusError error;
4552- const char *name, *old_owner, *new_owner;
4553-
4554- assert (connection != NULL);
4555- assert (message != NULL);
4556- assert (monitor != NULL);
4557-
4558- dbus_error_init (&error);
4559- if (dbus_message_get_args (message, &error,
4560- DBUS_TYPE_STRING, &name,
4561- DBUS_TYPE_STRING, &old_owner,
4562- DBUS_TYPE_STRING, &new_owner,
4563- DBUS_TYPE_INVALID) &&
4564- strcmp (name, UPSTART_SERVICE) == 0)
4565- {
4566- if (new_owner)
4567- ply_trace ("owner changed from '%s' to '%s'", old_owner, new_owner);
4568- else
4569- ply_trace ("owner left bus");
4570- free (monitor->owner);
4571- monitor->owner = new_owner ? strdup (new_owner) : NULL;
4572- }
4573-
4574- return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; /* let other handlers try */
4575-}
4576
4577 static DBusHandlerResult
4578 job_added_handler (DBusConnection *connection,
4579@@ -856,12 +780,6 @@
4580 if (path == NULL)
4581 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
4582
4583- if (dbus_message_is_signal (message, DBUS_INTERFACE_DBUS,
4584- "NameOwnerChanged") &&
4585- dbus_message_has_path (message, DBUS_PATH_DBUS) &&
4586- dbus_message_has_sender (message, DBUS_SERVICE_DBUS))
4587- return name_owner_changed_handler (connection, message, monitor);
4588-
4589 if (dbus_message_is_signal (message, UPSTART_INTERFACE_0_6,
4590 "JobAdded"))
4591 return job_added_handler (connection, message, monitor);
4592@@ -899,9 +817,7 @@
4593 DBusError error;
4594 DBusConnection *connection;
4595 ply_upstart_monitor_t *monitor;
4596- char *rule;
4597 DBusMessage *message;
4598- const char *monitor_service = UPSTART_SERVICE;
4599 DBusPendingCall *call;
4600
4601 dbus_error_init (&error);
4602@@ -909,7 +825,7 @@
4603 /* Get a connection to the system bus and set it up to listen for messages
4604 * from Upstart.
4605 */
4606- connection = dbus_bus_get (DBUS_BUS_SYSTEM, &error);
4607+ connection = dbus_connection_open (DBUS_ADDRESS_UPSTART, &error);
4608 if (connection == NULL)
4609 {
4610 ply_error ("unable to connect to system bus: %s", error.message);
4611@@ -938,52 +854,17 @@
4612 return NULL;
4613 }
4614
4615- asprintf (&rule, "type='%s',sender='%s',path='%s',"
4616- "interface='%s',member='%s',arg0='%s'",
4617- "signal", DBUS_SERVICE_DBUS, DBUS_PATH_DBUS,
4618- DBUS_INTERFACE_DBUS, "NameOwnerChanged", UPSTART_SERVICE);
4619- dbus_bus_add_match (connection, rule, &error);
4620- free (rule);
4621- if (dbus_error_is_set (&error))
4622- {
4623- ply_error ("unable to add match rule to system bus connection: %s",
4624- error.message);
4625- ply_upstart_monitor_free (monitor);
4626- dbus_error_free (&error);
4627- return NULL;
4628- }
4629-
4630- asprintf (&rule, "type='%s',sender='%s'", "signal", UPSTART_SERVICE);
4631- dbus_bus_add_match (connection, rule, &error);
4632- free (rule);
4633- if (dbus_error_is_set (&error))
4634- {
4635- ply_error ("unable to add match rule to system bus connection: %s",
4636- error.message);
4637- ply_upstart_monitor_free (monitor);
4638- dbus_error_free (&error);
4639- return NULL;
4640- }
4641-
4642- /* Start the state machine going: find out the current owner of the
4643- * well-known Upstart name.
4644- * Ignore errors: the worst case is that we don't get any messages back
4645- * and our state machine does nothing.
4646- */
4647- ply_trace ("calling GetNameOwner");
4648- message = dbus_message_new_method_call (DBUS_SERVICE_DBUS, DBUS_PATH_DBUS,
4649- DBUS_INTERFACE_DBUS, "GetNameOwner");
4650- dbus_message_append_args (message,
4651- DBUS_TYPE_STRING, &monitor_service,
4652- DBUS_TYPE_INVALID);
4653- dbus_connection_send_with_reply (connection, message, &call, -1);
4654+ ply_trace ("calling GetAllJobs");
4655+ message = dbus_message_new_method_call (UPSTART_SERVICE, UPSTART_PATH,
4656+ UPSTART_INTERFACE_0_6,
4657+ "GetAllJobs");
4658+ dbus_connection_send_with_reply (monitor->connection, message, &call, -1);
4659 dbus_message_unref (message);
4660 if (call != NULL)
4661 dbus_pending_call_set_notify (call,
4662 (DBusPendingCallNotifyFunction)
4663- on_get_name_owner_finished,
4664- monitor,
4665- NULL);
4666+ on_get_all_jobs_finished,
4667+ monitor, NULL);
4668
4669 if (loop != NULL)
4670 ply_upstart_monitor_connect_to_event_loop (monitor, loop);
4671
4672=== modified file 'src/upstart-bridge/plymouth-upstart-bridge.c'
4673--- src/upstart-bridge/plymouth-upstart-bridge.c 2011-03-12 22:54:53 +0000
4674+++ src/upstart-bridge/plymouth-upstart-bridge.c 2014-03-14 10:43:52 +0000
4675@@ -307,7 +307,9 @@
4676 if (should_be_verbose && !ply_is_tracing ())
4677 ply_toggle_tracing ();
4678
4679- setupterm (NULL, STDOUT_FILENO, NULL);
4680+ /* Don't bail on dummy/hardcopy terminals */
4681+ int errret=0;
4682+ setupterm (NULL, STDOUT_FILENO, &errret);
4683
4684 is_connected = ply_boot_client_connect (state.client,
4685 (ply_boot_client_disconnect_handler_t)
4686
4687=== modified file 'themes/ubuntu-logo/Makefile.am'
4688--- themes/ubuntu-logo/Makefile.am 2011-04-15 13:35:04 +0000
4689+++ themes/ubuntu-logo/Makefile.am 2014-03-14 10:43:52 +0000
4690@@ -1,6 +1,7 @@
4691 themedir = $(datadir)/plymouth/themes/ubuntu-logo
4692-nodist_theme_DATA = ubuntu-logo.plymouth
4693+nodist_theme_DATA = ubuntu-logo.plymouth ubuntu-logo-scale-2.plymouth
4694 dist_theme_DATA = ubuntu-logo.script \
4695+ ubuntu-logo-scale-2.script \
4696 ubuntu-logo.grub \
4697 ubuntu_logo.png \
4698 ubuntu_logo16.png \
4699@@ -13,11 +14,23 @@
4700
4701
4702
4703-MAINTAINERCLEANFILES = Makefile.in ubuntu-logo.plymouth
4704-CLEANFILES = ubuntu-logo.plymouth
4705+MAINTAINERCLEANFILES = Makefile.in ubuntu-logo.plymouth ubuntu-logo-scale-2.plymouth ubuntu-logo.script ubuntu-logo-scale-2.script
4706+CLEANFILES = ubuntu-logo.plymouth ubuntu-logo-scale-2.plymouth ubuntu-logo.script ubuntu-logo-scale-2.script
4707
4708 ubuntu-logo.plymouth: $(srcdir)/ubuntu-logo.plymouth.in
4709- sed -e 's,[@]PLYMOUTH_THEME_PATH[@],$(PLYMOUTH_THEME_PATH),g' \
4710+ sed -e 's,[@]PLYMOUTH_THEME_PATH[@],$(PLYMOUTH_THEME_PATH),g;s,[@]EXTRA_NAME[@],,g;s,[@]SCRIPT_NAME[@],ubuntu-logo,g' \
4711 $(srcdir)/ubuntu-logo.plymouth.in > ubuntu-logo.plymouth
4712
4713-EXTRA_DIST = ubuntu-logo.plymouth.in
4714+ubuntu-logo-scale-2.plymouth: $(srcdir)/ubuntu-logo.plymouth.in
4715+ sed -e 's,[@]PLYMOUTH_THEME_PATH[@],$(PLYMOUTH_THEME_PATH),g;s,[@]EXTRA_NAME[@],(Scale x2),g;s,[@]SCRIPT_NAME[@],ubuntu-logo-scale-2,g' \
4716+ $(srcdir)/ubuntu-logo.plymouth.in > ubuntu-logo-scale-2.plymouth
4717+
4718+ubuntu-logo.script: $(srcdir)/ubuntu-logo.script.in
4719+ sed -e 's,[@]SCALEFACTOR[@],1,g' \
4720+ $(srcdir)/ubuntu-logo.script.in > ubuntu-logo.script
4721+
4722+ubuntu-logo-scale-2.script: $(srcdir)/ubuntu-logo.script.in
4723+ sed -e 's,[@]SCALEFACTOR[@],2,g' \
4724+ $(srcdir)/ubuntu-logo.script.in > ubuntu-logo-scale-2.script
4725+
4726+EXTRA_DIST = ubuntu-logo.plymouth.in ubuntu-logo.script.in
4727
4728=== modified file 'themes/ubuntu-logo/ubuntu-logo.plymouth.in'
4729--- themes/ubuntu-logo/ubuntu-logo.plymouth.in 2009-12-07 19:55:24 +0000
4730+++ themes/ubuntu-logo/ubuntu-logo.plymouth.in 2014-03-14 10:43:52 +0000
4731@@ -1,8 +1,8 @@
4732 [Plymouth Theme]
4733-Name=Ubuntu Logo
4734+Name=Ubuntu Logo @EXTRA_NAME@
4735 Description=A theme that features a blank background with a logo.
4736 ModuleName=script
4737
4738 [script]
4739 ImageDir=@PLYMOUTH_THEME_PATH@/ubuntu-logo
4740-ScriptFile=@PLYMOUTH_THEME_PATH@/ubuntu-logo/ubuntu-logo.script
4741+ScriptFile=@PLYMOUTH_THEME_PATH@/ubuntu-logo/@SCRIPT_NAME@.script
4742
4743=== renamed file 'themes/ubuntu-logo/ubuntu-logo.script' => 'themes/ubuntu-logo/ubuntu-logo.script.in'
4744--- themes/ubuntu-logo/ubuntu-logo.script 2013-02-14 00:56:49 +0000
4745+++ themes/ubuntu-logo/ubuntu-logo.script.in 2014-03-14 10:43:52 +0000
4746@@ -46,12 +46,27 @@
4747 debugsprite_bottom = Sprite();
4748 debugsprite_medium = Sprite();
4749
4750+# Ubuntu Font
4751+ubuntufont = "Ubuntu 11";
4752+ubuntualignment = "center";
4753+
4754+# Scale factor
4755+scalefactor = @SCALEFACTOR@;
4756+
4757 # are we currently prompting for a password?
4758 prompt_active = 0;
4759
4760+# Generic scalable image loader
4761+fun LoadScaleImage (imagepath) {
4762+ image = Image (imagepath);
4763+ image = image.Scale (image.GetWidth() * scalefactor, image.GetHeight() * scalefactor);
4764+ return image;
4765+}
4766+
4767 # General purpose function to create text
4768 fun WriteText (text, colour) {
4769- image = Image.Text (text, colour.red, colour.green, colour.blue);
4770+ image = Image.Text (text, colour.red, colour.green, colour.blue, color.alpha, ubuntufont, ubuntualignment);
4771+ image = image.Scale (image.GetWidth() * scalefactor, image.GetHeight() * scalefactor);
4772 return image;
4773 }
4774
4775@@ -184,7 +199,7 @@
4776 question_field_filename = "password_field.png";
4777 }
4778
4779-logo.image = Image (logo_filename);
4780+logo.image = LoadScaleImage (logo_filename);
4781 logo.sprite = Sprite ();
4782 logo.sprite.SetImage (logo.image);
4783 logo.width = logo.image.GetWidth ();
4784@@ -206,8 +221,8 @@
4785
4786 status = "normal";
4787
4788-progress_indicator.bullet_off = Image (progress_dot_off_filename);
4789-progress_indicator.bullet_on = Image (progress_dot_on_filename);
4790+progress_indicator.bullet_off = LoadScaleImage (progress_dot_off_filename);
4791+progress_indicator.bullet_on = LoadScaleImage (progress_dot_on_filename);
4792 progress_indicator.bullet_width = progress_indicator.bullet_off.GetWidth ();
4793 progress_indicator.bullet_height = progress_indicator.bullet_off.GetHeight ();
4794 progress_indicator.bullet_hspacing = progress_indicator.bullet_width * 1.1;
4795@@ -509,9 +524,8 @@
4796
4797 local.entry;
4798 local.bullet_image;
4799-
4800- bullet_image = Image (progress_dot_off_filename);
4801- entry.image = Image (password_field_filename);
4802+ bullet_image = LoadScaleImage (progress_dot_off_filename);
4803+ entry.image = LoadScaleImage (password_field_filename);
4804
4805 # Hide the normal labels
4806 prompt_active = 1;
4807@@ -1010,9 +1024,9 @@
4808 local.content;
4809 local.margin;
4810
4811- field.image = Image (question_field_filename);
4812+ field.image = LoadScaleImage (question_field_filename);
4813 content = Sprite ();
4814- bullet_image = Image (progress_dot_off_filename);
4815+ bullet_image = LoadScaleImage (progress_dot_off_filename);
4816 margin = bullet_image.GetWidth() / 2;
4817
4818 # Hide the normal labels

Subscribers

People subscribed via source and target branches