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
=== modified file '.pc/applied-patches'
--- .pc/applied-patches 2013-12-02 04:53:37 +0000
+++ .pc/applied-patches 2014-03-14 10:43:52 +0000
@@ -13,3 +13,7 @@
13Miscellaneous-fixes-for-compiler-warnings.patch13Miscellaneous-fixes-for-compiler-warnings.patch
14autoreconf.patch14autoreconf.patch
15details-update-status.patch15details-update-status.patch
16use-upstart-private-socket.patch
17dont-bail-on-dummy-terms.patch
18no-print-empty-description.patch
19ubuntu-logo-scale-factor-2.patch
1620
=== added directory '.pc/dont-bail-on-dummy-terms.patch'
=== added directory '.pc/dont-bail-on-dummy-terms.patch/src'
=== added directory '.pc/dont-bail-on-dummy-terms.patch/src/upstart-bridge'
=== added file '.pc/dont-bail-on-dummy-terms.patch/src/upstart-bridge/plymouth-upstart-bridge.c'
--- .pc/dont-bail-on-dummy-terms.patch/src/upstart-bridge/plymouth-upstart-bridge.c 1970-01-01 00:00:00 +0000
+++ .pc/dont-bail-on-dummy-terms.patch/src/upstart-bridge/plymouth-upstart-bridge.c 2014-03-14 10:43:52 +0000
@@ -0,0 +1,339 @@
1/* plymouth-upstart-bridge.c - bridge Upstart job state changes to Plymouth
2 *
3 * Copyright (C) 2010, 2011 Canonical Ltd.
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2, or (at your option)
8 * any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
18 * 02111-1307, USA.
19 *
20 * Written by: Colin Watson <cjwatson@ubuntu.com>
21 */
22#include "config.h"
23
24#include <stdbool.h>
25#include <signal.h>
26#include <stdlib.h>
27#include <stdio.h>
28#include <string.h>
29#include <unistd.h>
30
31#if defined(HAVE_NCURSESW_TERM_H)
32#include <ncursesw/term.h>
33#elif defined(HAVE_NCURSES_TERM_H)
34#include <ncurses/term.h>
35#else
36#include <term.h>
37#endif
38
39#include "ply-boot-client.h"
40#include "ply-command-parser.h"
41#include "ply-event-loop.h"
42#include "ply-logger.h"
43#include "ply-upstart-monitor.h"
44
45typedef struct
46{
47 ply_event_loop_t *loop;
48 ply_boot_client_t *client;
49 ply_upstart_monitor_t *upstart;
50 ply_command_parser_t *command_parser;
51} state_t;
52
53#ifndef TERMINAL_COLOR_RED
54#define TERMINAL_COLOR_RED 1
55#endif
56
57/* We don't care about the difference between "not a string capability" and
58 * "cancelled or absent".
59 */
60static const char *
61get_string_capability (const char *name)
62{
63 const char *value;
64
65 value = tigetstr ((char *) name);
66 if (value == (const char *) -1)
67 value = NULL;
68
69 return value;
70}
71
72static bool
73terminal_ignores_new_line_after_80_chars (void)
74{
75 return tigetflag ((char *) "xenl") != 0;
76}
77
78static int
79get_number_of_columns (void)
80{
81 int number_of_columns;
82
83 number_of_columns = tigetnum ((char *) "cols");
84
85 return number_of_columns;
86}
87
88static bool
89can_set_cursor_column (void)
90{
91 const char *capability;
92
93 capability = get_string_capability ("hpa");
94
95 return capability != NULL;
96}
97
98static void
99set_cursor_column (int column)
100{
101 const char *capability;
102 const char *terminal_string;
103
104 capability = get_string_capability ("hpa");
105 terminal_string = tiparm (capability, column);
106 fputs (terminal_string, stdout);
107}
108
109static bool
110can_set_fg_color (void)
111{
112 const char *capability;
113
114 capability = get_string_capability ("setaf");
115
116 return capability != NULL;
117}
118
119static void
120set_fg_color (int color)
121{
122 const char *capability;
123 const char *terminal_string;
124
125 capability = get_string_capability ("setaf");
126 terminal_string = tiparm (capability, color);
127 fputs (terminal_string, stdout);
128}
129
130static void
131unset_fg_color (void)
132{
133 const char *terminal_string;
134
135 terminal_string = get_string_capability ("op");
136
137 if (terminal_string == NULL)
138 return;
139
140 fputs (terminal_string, stdout);
141}
142
143static void
144update_status (state_t *state,
145 ply_upstart_monitor_job_properties_t *job,
146 ply_upstart_monitor_instance_properties_t *instance,
147 const char *action,
148 bool is_okay)
149{
150 ply_boot_client_update_daemon (state->client, job->name, NULL, NULL, state);
151
152 if (job->description == NULL)
153 return;
154
155 printf (" * %s%s%s",
156 action ? action : "", action ? " " : "", job->description);
157
158 if (terminal_ignores_new_line_after_80_chars () && can_set_cursor_column ())
159 {
160 int number_of_columns, column;
161
162 number_of_columns = get_number_of_columns ();
163
164 if (number_of_columns < (int) strlen("[fail]"))
165 number_of_columns = 80;
166
167 column = number_of_columns - strlen ("[fail]") - 1;
168
169 set_cursor_column (column);
170
171 if (is_okay)
172 puts ("[ OK ]");
173 else
174 {
175 bool supports_color;
176
177 supports_color = can_set_fg_color ();
178
179 fputs ("[", stdout);
180
181 if (supports_color)
182 set_fg_color (TERMINAL_COLOR_RED);
183
184 fputs ("fail", stdout);
185
186 if (supports_color)
187 unset_fg_color ();
188
189 puts ("]");
190 }
191 }
192 else
193 {
194 if (is_okay)
195 puts (" ...done.");
196 else
197 puts (" ...fail!");
198 }
199}
200
201static void
202on_failed (void *data,
203 ply_upstart_monitor_job_properties_t *job,
204 ply_upstart_monitor_instance_properties_t *instance,
205 int status)
206{
207 state_t *state = data;
208
209 if (job->is_task)
210 update_status (state, job, instance, NULL, false);
211 else
212 {
213 if (strcmp (instance->goal, "start") == 0)
214 update_status (state, job, instance, "Starting", false);
215 else if (strcmp (instance->goal, "stop") == 0)
216 update_status (state, job, instance, "Stopping", false);
217 }
218}
219
220static void
221on_state_changed (state_t *state,
222 const char *old_state,
223 ply_upstart_monitor_job_properties_t *job,
224 ply_upstart_monitor_instance_properties_t *instance)
225{
226 if (instance->failed)
227 return;
228
229 if (job->is_task)
230 {
231 if (strcmp (instance->state, "waiting") == 0)
232 update_status (state, job, instance, NULL, true);
233 }
234 else
235 {
236 if (strcmp (instance->goal, "start") == 0)
237 {
238 if (strcmp (instance->state, "running") == 0)
239 update_status (state, job, instance, "Starting", true);
240 }
241 else if (strcmp (instance->goal, "stop") == 0)
242 {
243 if (strcmp (instance->state, "waiting") == 0)
244 update_status (state, job, instance, "Stopping", true);
245 }
246 }
247}
248
249static void
250on_disconnect (state_t *state)
251{
252 ply_trace ("disconnected from boot status daemon");
253 ply_event_loop_exit (state->loop, 0);
254}
255
256int
257main (int argc,
258 char **argv)
259{
260 state_t state = { 0 };
261 bool should_help, should_be_verbose;
262 bool is_connected;
263 int exit_code;
264
265 exit_code = 0;
266
267 signal (SIGPIPE, SIG_IGN);
268
269 state.loop = ply_event_loop_new ();
270 state.client = ply_boot_client_new ();
271 state.command_parser = ply_command_parser_new ("plymouth-upstart-bridge", "Upstart job state bridge");
272
273 ply_command_parser_add_options (state.command_parser,
274 "help", "This help message", PLY_COMMAND_OPTION_TYPE_FLAG,
275 "debug", "Enable verbose debug logging", PLY_COMMAND_OPTION_TYPE_FLAG,
276 NULL);
277
278 if (!ply_command_parser_parse_arguments (state.command_parser, state.loop, argv, argc))
279 {
280 char *help_string;
281
282 help_string = ply_command_parser_get_help_string (state.command_parser);
283
284 ply_error ("%s", help_string);
285
286 free (help_string);
287 return 1;
288 }
289
290 ply_command_parser_get_options (state.command_parser,
291 "help", &should_help,
292 "debug", &should_be_verbose,
293 NULL);
294
295 if (should_help)
296 {
297 char *help_string;
298
299 help_string = ply_command_parser_get_help_string (state.command_parser);
300
301 puts (help_string);
302
303 free (help_string);
304 return 0;
305 }
306
307 if (should_be_verbose && !ply_is_tracing ())
308 ply_toggle_tracing ();
309
310 setupterm (NULL, STDOUT_FILENO, NULL);
311
312 is_connected = ply_boot_client_connect (state.client,
313 (ply_boot_client_disconnect_handler_t)
314 on_disconnect, &state);
315 if (!is_connected)
316 {
317 ply_trace ("daemon not running");
318 return 1;
319 }
320
321 ply_boot_client_attach_to_event_loop (state.client, state.loop);
322 state.upstart = ply_upstart_monitor_new (state.loop);
323 if (!state.upstart)
324 return 1;
325 ply_upstart_monitor_add_state_changed_handler (state.upstart,
326 (ply_upstart_monitor_state_changed_handler_t)
327 on_state_changed, &state);
328 ply_upstart_monitor_add_failed_handler (state.upstart, on_failed, &state);
329
330 exit_code = ply_event_loop_run (state.loop);
331
332 ply_upstart_monitor_free (state.upstart);
333 ply_boot_client_free (state.client);
334
335 ply_event_loop_free (state.loop);
336
337 return exit_code;
338}
339/* vim: set ts=4 sw=4 expandtab autoindent cindent cino={.5s,(0: */
0340
=== added directory '.pc/no-print-empty-description.patch'
=== added directory '.pc/no-print-empty-description.patch/src'
=== added directory '.pc/no-print-empty-description.patch/src/upstart-bridge'
=== added file '.pc/no-print-empty-description.patch/src/upstart-bridge/ply-upstart-monitor.c'
--- .pc/no-print-empty-description.patch/src/upstart-bridge/ply-upstart-monitor.c 1970-01-01 00:00:00 +0000
+++ .pc/no-print-empty-description.patch/src/upstart-bridge/ply-upstart-monitor.c 2014-03-14 10:43:52 +0000
@@ -0,0 +1,1182 @@
1/* ply-upstart-monitor.c - Upstart D-Bus monitor
2 *
3 * Copyright (C) 2010, 2011 Canonical Ltd.
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2, or (at your option)
8 * any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
18 * 02111-1307, USA.
19 *
20 * Written by: Colin Watson <cjwatson@ubuntu.com>
21 */
22#include "config.h"
23#include "ply-upstart-monitor.h"
24
25#include <assert.h>
26#include <stdbool.h>
27#include <stdlib.h>
28#include <stdio.h>
29#include <string.h>
30#include <sys/eventfd.h>
31
32#include <dbus/dbus.h>
33
34#include "ply-logger.h"
35#include "ply-event-loop.h"
36#include "ply-hashtable.h"
37#include "ply-list.h"
38#include "ply-utils.h"
39
40typedef struct
41{
42 ply_upstart_monitor_t *monitor;
43 DBusTimeout *timeout;
44} ply_upstart_monitor_timeout_t;
45
46struct _ply_upstart_monitor
47{
48 DBusConnection *connection;
49 ply_event_loop_t *loop;
50 ply_hashtable_t *jobs;
51 ply_hashtable_t *all_instances;
52 ply_upstart_monitor_state_changed_handler_t state_changed_handler;
53 void *state_changed_data;
54 ply_upstart_monitor_failed_handler_t failed_handler;
55 void *failed_data;
56 int dispatch_fd;
57};
58
59typedef struct
60{
61 ply_upstart_monitor_t *monitor;
62 ply_upstart_monitor_job_properties_t properties;
63 ply_hashtable_t *instances;
64 ply_list_t *pending_calls;
65} ply_upstart_monitor_job_t;
66
67typedef struct
68{
69 ply_upstart_monitor_job_t *job;
70 ply_upstart_monitor_instance_properties_t properties;
71 ply_list_t *pending_calls;
72 uint32_t state_changed : 1;
73 uint32_t call_failed : 1;
74} ply_upstart_monitor_instance_t;
75
76#define UPSTART_SERVICE NULL
77#define DBUS_ADDRESS_UPSTART "unix:abstract=/com/ubuntu/upstart"
78#define UPSTART_PATH "/com/ubuntu/Upstart"
79#define UPSTART_INTERFACE_0_6 "com.ubuntu.Upstart0_6"
80#define UPSTART_INTERFACE_0_6_JOB "com.ubuntu.Upstart0_6.Job"
81#define UPSTART_INTERFACE_0_6_INSTANCE "com.ubuntu.Upstart0_6.Instance"
82
83/* Remove an entry from a hashtable, free the key, and return the data. */
84static void *
85hashtable_remove_and_free_key (ply_hashtable_t *hashtable,
86 const void *key)
87{
88 void *reply_key, *reply_data;
89
90 if (!ply_hashtable_lookup_full (hashtable, (void *) key,
91 &reply_key, &reply_data))
92 return NULL;
93 ply_hashtable_remove (hashtable, (void *) key);
94 free (reply_key);
95
96 return reply_data;
97}
98
99/* We assume, in general, that Upstart responds to D-Bus messages in a
100 * single thread, and that it processes messages on a given connection in
101 * the order in which they were sent. Taken together, these assumptions
102 * imply a kind of coherence: a Properties.GetAll reply received after a
103 * StateChanged signal must have been computed entirely after the state
104 * change. Thus, if this function returns false (properties have not been
105 * fetched yet), it should be safe to record an event as call until such
106 * time as the properties of the instance are known.
107 */
108static bool
109instance_is_initialized (ply_upstart_monitor_instance_t *instance)
110{
111 /* Note that the job may not have a description. */
112 if (instance->job->properties.name &&
113 instance->properties.name && instance->properties.goal &&
114 instance->properties.state)
115 return true;
116 else
117 return false;
118}
119
120static void
121on_get_all_instance_properties_finished (DBusPendingCall *call,
122 ply_upstart_monitor_instance_t *instance)
123{
124 DBusMessage *reply;
125 DBusMessageIter iter, array_iter, dict_iter, variant_iter;
126 const char *key, *name, *goal, *state;
127 ply_upstart_monitor_t *monitor;
128
129 assert (call != NULL);
130 assert (instance != NULL);
131
132 reply = dbus_pending_call_steal_reply (call);
133 if (reply == NULL)
134 return;
135 if (dbus_message_get_type (reply) != DBUS_MESSAGE_TYPE_METHOD_RETURN)
136 goto out;
137
138 dbus_message_iter_init (reply, &iter);
139 if (dbus_message_iter_get_arg_type (&iter) != DBUS_TYPE_ARRAY)
140 goto out;
141 dbus_message_iter_recurse (&iter, &array_iter);
142
143 while (dbus_message_iter_get_arg_type (&array_iter) == DBUS_TYPE_DICT_ENTRY)
144 {
145 dbus_message_iter_recurse (&array_iter, &dict_iter);
146
147 if (dbus_message_iter_get_arg_type (&dict_iter) != DBUS_TYPE_STRING)
148 goto next_item;
149
150 dbus_message_iter_get_basic (&dict_iter, &key);
151 if (key == NULL)
152 goto next_item;
153
154 dbus_message_iter_next (&dict_iter);
155 if (dbus_message_iter_get_arg_type (&dict_iter) != DBUS_TYPE_VARIANT)
156 goto next_item;
157 dbus_message_iter_recurse (&dict_iter, &variant_iter);
158 if (dbus_message_iter_get_arg_type (&variant_iter) != DBUS_TYPE_STRING)
159 goto next_item;
160
161 if (strcmp (key, "name") == 0)
162 {
163 dbus_message_iter_get_basic (&variant_iter, &name);
164 if (name != NULL)
165 {
166 ply_trace ("%s: name = '%s'",
167 instance->job->properties.name, name);
168 instance->properties.name = strdup (name);
169 }
170 }
171 else if (strcmp (key, "goal") == 0)
172 {
173 dbus_message_iter_get_basic (&variant_iter, &goal);
174 if (goal != NULL)
175 {
176 ply_trace ("%s: goal = '%s'",
177 instance->job->properties.name, goal);
178 instance->properties.goal = strdup (goal);
179 }
180 }
181 else if (strcmp (key, "state") == 0)
182 {
183 dbus_message_iter_get_basic (&variant_iter, &state);
184 if (state != NULL)
185 {
186 ply_trace ("%s: state = '%s'",
187 instance->job->properties.name, state);
188 instance->properties.state = strdup (state);
189 }
190 }
191
192next_item:
193 dbus_message_iter_next (&array_iter);
194 }
195
196out:
197 dbus_message_unref (reply);
198
199 if (instance_is_initialized (instance))
200 {
201 /* Process any call events. */
202 monitor = instance->job->monitor;
203
204 if (instance->state_changed && monitor->state_changed_handler)
205 monitor->state_changed_handler (monitor->state_changed_data, NULL,
206 &instance->job->properties,
207 &instance->properties);
208 instance->state_changed = false;
209
210 if (instance->call_failed && monitor->failed_handler)
211 monitor->failed_handler (monitor->failed_data,
212 &instance->job->properties,
213 &instance->properties,
214 instance->properties.failed);
215 instance->call_failed = false;
216 }
217}
218
219static void
220on_get_all_job_properties_finished (DBusPendingCall *call,
221 ply_upstart_monitor_job_t *job)
222{
223 DBusMessage *reply;
224 DBusMessageIter iter, array_iter, dict_iter, variant_iter;
225 const char *key, *name, *description;
226 dbus_uint32_t task;
227
228 assert (call != NULL);
229 assert (job != NULL);
230
231 reply = dbus_pending_call_steal_reply (call);
232 if (reply == NULL)
233 return;
234 if (dbus_message_get_type (reply) != DBUS_MESSAGE_TYPE_METHOD_RETURN)
235 goto out;
236
237 dbus_message_iter_init (reply, &iter);
238 if (dbus_message_iter_get_arg_type (&iter) != DBUS_TYPE_ARRAY)
239 goto out;
240 dbus_message_iter_recurse (&iter, &array_iter);
241
242 while (dbus_message_iter_get_arg_type (&array_iter) == DBUS_TYPE_DICT_ENTRY)
243 {
244 dbus_message_iter_recurse (&array_iter, &dict_iter);
245
246 if (dbus_message_iter_get_arg_type (&dict_iter) != DBUS_TYPE_STRING)
247 goto next_item;
248
249 dbus_message_iter_get_basic (&dict_iter, &key);
250 if (key == NULL)
251 goto next_item;
252
253 dbus_message_iter_next (&dict_iter);
254 if (dbus_message_iter_get_arg_type (&dict_iter) != DBUS_TYPE_VARIANT)
255 goto next_item;
256 dbus_message_iter_recurse (&dict_iter, &variant_iter);
257
258 if (strcmp (key, "name") == 0)
259 {
260 if (dbus_message_iter_get_arg_type (&variant_iter) !=
261 DBUS_TYPE_STRING)
262 goto next_item;
263 dbus_message_iter_get_basic (&variant_iter, &name);
264 if (name != NULL)
265 {
266 ply_trace ("name = '%s'", name);
267 job->properties.name = strdup (name);
268 }
269 }
270 else if (strcmp (key, "description") == 0)
271 {
272 if (dbus_message_iter_get_arg_type (&variant_iter) !=
273 DBUS_TYPE_STRING)
274 goto next_item;
275 dbus_message_iter_get_basic (&variant_iter, &description);
276 if (description != NULL)
277 {
278 ply_trace ("description = '%s'", description);
279 job->properties.description = strdup (description);
280 }
281 }
282 else if (strcmp (key, "task") == 0)
283 {
284 if (dbus_message_iter_get_arg_type (&variant_iter) !=
285 DBUS_TYPE_BOOLEAN)
286 goto next_item;
287 dbus_message_iter_get_basic (&variant_iter, &task);
288 ply_trace ("task = %s", task ? "TRUE" : "FALSE");
289 job->properties.is_task = task ? true : false;
290 }
291
292next_item:
293 dbus_message_iter_next (&array_iter);
294 }
295
296out:
297 dbus_message_unref (reply);
298}
299
300static void
301remove_instance_internal (ply_upstart_monitor_job_t *job, const char *path)
302{
303 ply_upstart_monitor_instance_t *instance;
304 ply_list_node_t *node;
305
306 instance = hashtable_remove_and_free_key (job->instances, path);
307 if (instance == NULL)
308 return;
309 hashtable_remove_and_free_key (job->monitor->all_instances, path);
310
311 node = ply_list_get_first_node (instance->pending_calls);
312 while (node != NULL)
313 {
314 DBusPendingCall *call;
315 ply_list_node_t *next_node;
316
317 call = ply_list_node_get_data (node);
318 next_node = ply_list_get_next_node (instance->pending_calls, node);
319 dbus_pending_call_cancel (call);
320 dbus_pending_call_unref (call);
321 node = next_node;
322 }
323 ply_list_free (instance->pending_calls);
324
325 free (instance->properties.name);
326 free (instance->properties.goal);
327 free (instance->properties.state);
328 free (instance);
329}
330
331static void
332add_instance (ply_upstart_monitor_job_t *job,
333 const char *path)
334{
335 ply_upstart_monitor_instance_t *instance;
336 DBusMessage *message;
337 const char *interface = UPSTART_INTERFACE_0_6_INSTANCE;
338 DBusPendingCall *call;
339
340 ply_trace ("adding instance: %s", path);
341
342 remove_instance_internal (job, path);
343
344 instance = calloc (1, sizeof (ply_upstart_monitor_instance_t));
345 instance->job = job;
346 instance->properties.name = NULL;
347 instance->properties.goal = NULL;
348 instance->properties.state = NULL;
349 instance->properties.failed = false;
350 instance->pending_calls = ply_list_new ();
351 instance->state_changed = false;
352 instance->call_failed = false;
353
354 /* Keep a hash of instances per job, to make InstanceRemoved handling
355 * easy.
356 */
357 ply_hashtable_insert (job->instances, strdup (path), instance);
358 /* Keep a separate hash of all instances, to make StateChanged handling
359 * easy.
360 */
361 ply_hashtable_insert (job->monitor->all_instances, strdup (path), instance);
362
363 /* Ask Upstart for the name, goal, and state properties. */
364 ply_trace ("fetching properties of instance %s", path);
365 message = dbus_message_new_method_call (UPSTART_SERVICE, path,
366 DBUS_INTERFACE_PROPERTIES, "GetAll");
367 dbus_message_append_args (message,
368 DBUS_TYPE_STRING, &interface,
369 DBUS_TYPE_INVALID);
370 dbus_connection_send_with_reply (job->monitor->connection, message,
371 &call, -1);
372 dbus_message_unref (message);
373 if (call != NULL)
374 {
375 dbus_pending_call_set_notify (call,
376 (DBusPendingCallNotifyFunction)
377 on_get_all_instance_properties_finished,
378 instance, NULL);
379 ply_list_append_data (instance->pending_calls, call);
380 }
381}
382
383static void
384remove_instance (ply_upstart_monitor_job_t *job,
385 const char *path)
386{
387 ply_trace ("removing instance: %s", path);
388
389 remove_instance_internal (job, path);
390}
391
392static void
393on_get_all_instances_finished (DBusPendingCall *call,
394 ply_upstart_monitor_job_t *job)
395{
396 DBusMessage *reply;
397 DBusError error;
398 char **instances;
399 int n_instances, i;
400
401 assert (call != NULL);
402 assert (job != NULL);
403
404 reply = dbus_pending_call_steal_reply (call);
405 if (reply == NULL)
406 return;
407 if (dbus_message_get_type (reply) != DBUS_MESSAGE_TYPE_METHOD_RETURN)
408 goto out;
409
410 dbus_error_init (&error);
411 dbus_message_get_args (reply, &error,
412 DBUS_TYPE_ARRAY, DBUS_TYPE_OBJECT_PATH,
413 &instances, &n_instances,
414 DBUS_TYPE_INVALID);
415 if (dbus_error_is_set (&error))
416 goto out;
417 dbus_error_free (&error);
418
419 for (i = 0; i < n_instances; ++i)
420 add_instance (job, instances[i]);
421
422 dbus_free_string_array (instances);
423
424out:
425 dbus_message_unref (reply);
426}
427
428static void
429free_job_instance (void *key, void *data, void *user_data)
430{
431 const char *path = key;
432 ply_upstart_monitor_instance_t *instance = data;
433 ply_upstart_monitor_t *monitor = user_data;
434
435 assert (monitor != NULL);
436
437 if (instance == NULL)
438 return;
439
440 hashtable_remove_and_free_key (monitor->all_instances, path);
441 free (instance->properties.name);
442 free (instance->properties.goal);
443 free (instance->properties.state);
444 free (instance);
445}
446
447static void
448remove_job_internal (ply_upstart_monitor_t *monitor, const char *path)
449{
450 ply_upstart_monitor_job_t *job;
451 ply_list_node_t *node;
452
453 job = hashtable_remove_and_free_key (monitor->jobs, path);
454 if (job == NULL)
455 return;
456
457 node = ply_list_get_first_node (job->pending_calls);
458 while (node != NULL)
459 {
460 DBusPendingCall *call;
461 ply_list_node_t *next_node;
462
463 call = ply_list_node_get_data (node);
464 next_node = ply_list_get_next_node (job->pending_calls, node);
465 dbus_pending_call_cancel (call);
466 dbus_pending_call_unref (call);
467 node = next_node;
468 }
469 ply_list_free (job->pending_calls);
470
471 free (job->properties.name);
472 free (job->properties.description);
473 ply_hashtable_foreach (job->instances, free_job_instance, monitor);
474 ply_hashtable_free (job->instances);
475 free (job);
476}
477
478static void
479add_job (ply_upstart_monitor_t *monitor, const char *path)
480{
481 ply_upstart_monitor_job_t *job;
482 DBusMessage *message;
483 const char *interface = UPSTART_INTERFACE_0_6_JOB;
484 DBusPendingCall *call;
485
486 ply_trace ("adding job: %s", path);
487
488 remove_job_internal (monitor, path);
489
490 job = calloc (1, sizeof (ply_upstart_monitor_job_t));
491 job->monitor = monitor;
492 job->properties.name = NULL;
493 job->properties.description = NULL;
494 job->properties.is_task = false;
495 job->instances = ply_hashtable_new (ply_hashtable_string_hash,
496 ply_hashtable_string_compare);
497 job->pending_calls = ply_list_new ();
498
499 ply_hashtable_insert (monitor->jobs, strdup (path), job);
500
501 /* Ask Upstart for the name and description properties. */
502 ply_trace ("fetching properties of job %s", path);
503 message = dbus_message_new_method_call (UPSTART_SERVICE, path,
504 DBUS_INTERFACE_PROPERTIES, "GetAll");
505 dbus_message_append_args (message,
506 DBUS_TYPE_STRING, &interface,
507 DBUS_TYPE_INVALID);
508 dbus_connection_send_with_reply (monitor->connection, message, &call, -1);
509 dbus_message_unref (message);
510 if (call != NULL)
511 {
512 dbus_pending_call_set_notify (call,
513 (DBusPendingCallNotifyFunction)
514 on_get_all_job_properties_finished,
515 job,
516 NULL);
517 ply_list_append_data (job->pending_calls, call);
518 }
519
520 /* Ask Upstart for a list of all instances of this job. */
521 ply_trace ("calling GetAllInstances on job %s", path);
522 message = dbus_message_new_method_call (UPSTART_SERVICE, path,
523 UPSTART_INTERFACE_0_6_JOB,
524 "GetAllInstances");
525 dbus_connection_send_with_reply (monitor->connection, message, &call, -1);
526 dbus_message_unref (message);
527 if (call != NULL)
528 {
529 dbus_pending_call_set_notify (call,
530 (DBusPendingCallNotifyFunction)
531 on_get_all_instances_finished,
532 job,
533 NULL);
534 ply_list_append_data (job->pending_calls, call);
535 }
536}
537
538static void
539remove_job (ply_upstart_monitor_t *monitor, const char *path)
540{
541 ply_trace ("removing job: %s", path);
542
543 remove_job_internal (monitor, path);
544}
545
546static void
547on_get_all_jobs_finished (DBusPendingCall *call,
548 ply_upstart_monitor_t *monitor)
549{
550 DBusMessage *reply;
551 DBusError error;
552 char **jobs;
553 int n_jobs, i;
554
555 assert (call != NULL);
556 assert (monitor != NULL);
557
558 reply = dbus_pending_call_steal_reply (call);
559 if (reply == NULL)
560 return;
561 if (dbus_message_get_type (reply) != DBUS_MESSAGE_TYPE_METHOD_RETURN)
562 goto out;
563
564 dbus_error_init (&error);
565 dbus_message_get_args (reply, &error,
566 DBUS_TYPE_ARRAY, DBUS_TYPE_OBJECT_PATH,
567 &jobs, &n_jobs,
568 DBUS_TYPE_INVALID);
569 if (dbus_error_is_set (&error))
570 goto out;
571 dbus_error_free (&error);
572
573 for (i = 0; i < n_jobs; ++i)
574 add_job (monitor, jobs[i]);
575
576 dbus_free_string_array (jobs);
577
578out:
579 dbus_message_unref (reply);
580}
581
582
583static DBusHandlerResult
584job_added_handler (DBusConnection *connection,
585 DBusMessage *message,
586 ply_upstart_monitor_t *monitor)
587{
588 DBusError error;
589 const char *signal_path;
590
591 ply_trace ("got JobAdded");
592 dbus_error_init (&error);
593 if (dbus_message_get_args (message, &error,
594 DBUS_TYPE_OBJECT_PATH, &signal_path,
595 DBUS_TYPE_INVALID))
596 add_job (monitor, signal_path);
597 dbus_error_free (&error);
598 return DBUS_HANDLER_RESULT_HANDLED;
599}
600
601static DBusHandlerResult
602job_removed_handler (DBusConnection *connection,
603 DBusMessage *message,
604 ply_upstart_monitor_t *monitor)
605{
606 DBusError error;
607 const char *signal_path;
608
609 ply_trace ("got JobRemoved");
610 dbus_error_init (&error);
611 if (dbus_message_get_args (message, &error,
612 DBUS_TYPE_OBJECT_PATH, &signal_path,
613 DBUS_TYPE_INVALID))
614 remove_job (monitor, signal_path);
615 dbus_error_free (&error);
616 return DBUS_HANDLER_RESULT_HANDLED;
617}
618
619static DBusHandlerResult
620instance_added_handler (DBusConnection *connection, DBusMessage *message,
621 ply_upstart_monitor_t *monitor, const char *path)
622{
623 DBusError error;
624 const char *signal_path;
625 ply_upstart_monitor_job_t *job;
626
627 ply_trace ("got %s InstanceAdded", path);
628 job = ply_hashtable_lookup (monitor->jobs, (void *) path);
629 if (job != NULL)
630 {
631 dbus_error_init (&error);
632 if (dbus_message_get_args (message, &error,
633 DBUS_TYPE_OBJECT_PATH, &signal_path,
634 DBUS_TYPE_INVALID))
635 add_instance (job, signal_path);
636 dbus_error_free (&error);
637 }
638 return DBUS_HANDLER_RESULT_HANDLED;
639}
640
641static DBusHandlerResult
642instance_removed_handler (DBusConnection *connection, DBusMessage *message,
643 ply_upstart_monitor_t *monitor, const char *path)
644{
645 DBusError error;
646 const char *signal_path;
647 ply_upstart_monitor_job_t *job;
648
649 ply_trace ("got %s InstanceRemoved", path);
650 job = ply_hashtable_lookup (monitor->jobs, (void *) path);
651 if (job != NULL)
652 {
653 dbus_error_init (&error);
654 if (dbus_message_get_args (message, &error,
655 DBUS_TYPE_OBJECT_PATH, &signal_path,
656 DBUS_TYPE_INVALID))
657 remove_instance (job, signal_path);
658 dbus_error_free (&error);
659 }
660 return DBUS_HANDLER_RESULT_HANDLED;
661}
662
663static DBusHandlerResult
664goal_changed_handler (DBusConnection *connection, DBusMessage *message,
665 ply_upstart_monitor_t *monitor, const char *path)
666{
667 DBusError error;
668 const char *goal;
669 ply_upstart_monitor_instance_t *instance;
670 char *old_goal;
671
672 ply_trace ("got %s GoalChanged", path);
673 instance = ply_hashtable_lookup (monitor->all_instances, (void *) path);
674 if (instance != NULL)
675 {
676 dbus_error_init (&error);
677 if (dbus_message_get_args (message, &error,
678 DBUS_TYPE_STRING, &goal,
679 DBUS_TYPE_INVALID))
680 {
681 old_goal = instance->properties.goal;
682 instance->properties.goal = strdup (goal);
683 ply_trace ("goal changed from '%s' to '%s'", old_goal, goal);
684 free (old_goal);
685 }
686 dbus_error_free (&error);
687 }
688 return DBUS_HANDLER_RESULT_HANDLED;
689}
690
691static DBusHandlerResult
692state_changed_handler (DBusConnection *connection, DBusMessage *message,
693 ply_upstart_monitor_t *monitor, const char *path)
694{
695 DBusError error;
696 const char *state;
697 ply_upstart_monitor_instance_t *instance;
698 char *old_state;
699
700 ply_trace ("got %s StateChanged", path);
701 instance = ply_hashtable_lookup (monitor->all_instances, (void *) path);
702 if (instance != NULL)
703 {
704 dbus_error_init (&error);
705 if (dbus_message_get_args (message, &error,
706 DBUS_TYPE_STRING, &state,
707 DBUS_TYPE_INVALID))
708 {
709 old_state = instance->properties.state;
710 instance->properties.state = strdup (state);
711 ply_trace ("state changed from '%s' to '%s'", old_state, state);
712 if (strcmp (state, "starting") == 0)
713 {
714 /* Clear any old failed information. */
715 instance->properties.failed = 0;
716 instance->call_failed = false;
717 }
718 if (instance_is_initialized (instance))
719 {
720 if (monitor->state_changed_handler)
721 monitor->state_changed_handler (monitor->state_changed_data,
722 old_state,
723 &instance->job->properties,
724 &instance->properties);
725 }
726 else
727 instance->state_changed = true;
728 free (old_state);
729 }
730 dbus_error_free (&error);
731 }
732 return DBUS_HANDLER_RESULT_HANDLED;
733}
734
735static DBusHandlerResult
736failed_handler (DBusConnection *connection, DBusMessage *message,
737 ply_upstart_monitor_t *monitor, const char *path)
738{
739 DBusError error;
740 ply_upstart_monitor_instance_t *instance;
741 dbus_int32_t failed_status;
742
743 ply_trace ("got %s Failed", path);
744 instance = ply_hashtable_lookup (monitor->all_instances, (void *) path);
745 if (instance != NULL)
746 {
747 dbus_error_init (&error);
748 if (dbus_message_get_args (message, &error,
749 DBUS_TYPE_INT32, &failed_status,
750 DBUS_TYPE_INVALID))
751 {
752 instance->properties.failed = failed_status;
753 if (instance_is_initialized (instance))
754 {
755 if (monitor->failed_handler)
756 monitor->failed_handler (monitor->failed_data,
757 &instance->job->properties,
758 &instance->properties,
759 (int) failed_status);
760 }
761 else
762 instance->call_failed = true;
763 }
764 dbus_error_free (&error);
765 }
766 return DBUS_HANDLER_RESULT_HANDLED;
767}
768
769static DBusHandlerResult
770message_handler (DBusConnection *connection, DBusMessage *message, void *data)
771{
772 ply_upstart_monitor_t *monitor = data;
773 const char *path;
774
775 assert (connection != NULL);
776 assert (message != NULL);
777 assert (monitor != NULL);
778
779 path = dbus_message_get_path (message);
780 if (path == NULL)
781 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
782
783 if (dbus_message_is_signal (message, UPSTART_INTERFACE_0_6,
784 "JobAdded"))
785 return job_added_handler (connection, message, monitor);
786
787 if (dbus_message_is_signal (message, UPSTART_INTERFACE_0_6,
788 "JobRemoved"))
789 return job_removed_handler (connection, message, monitor);
790
791 if (dbus_message_is_signal (message, UPSTART_INTERFACE_0_6_JOB,
792 "InstanceAdded"))
793 return instance_added_handler (connection, message, monitor, path);
794
795 if (dbus_message_is_signal (message, UPSTART_INTERFACE_0_6_JOB,
796 "InstanceRemoved"))
797 return instance_removed_handler (connection, message, monitor, path);
798
799 if (dbus_message_is_signal (message, UPSTART_INTERFACE_0_6_INSTANCE,
800 "GoalChanged"))
801 return goal_changed_handler (connection, message, monitor, path);
802
803 if (dbus_message_is_signal (message, UPSTART_INTERFACE_0_6_INSTANCE,
804 "StateChanged"))
805 return state_changed_handler (connection, message, monitor, path);
806
807 if (dbus_message_is_signal (message, UPSTART_INTERFACE_0_6_INSTANCE,
808 "Failed"))
809 return failed_handler (connection, message, monitor, path);
810
811 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
812}
813
814ply_upstart_monitor_t *
815ply_upstart_monitor_new (ply_event_loop_t *loop)
816{
817 DBusError error;
818 DBusConnection *connection;
819 ply_upstart_monitor_t *monitor;
820 DBusMessage *message;
821 DBusPendingCall *call;
822
823 dbus_error_init (&error);
824
825 /* Get a connection to the system bus and set it up to listen for messages
826 * from Upstart.
827 */
828 connection = dbus_connection_open (DBUS_ADDRESS_UPSTART, &error);
829 if (connection == NULL)
830 {
831 ply_error ("unable to connect to system bus: %s", error.message);
832 dbus_error_free (&error);
833 return NULL;
834 }
835 dbus_error_free (&error);
836
837 monitor = calloc (1, sizeof (ply_upstart_monitor_t));
838 monitor->connection = connection;
839 monitor->loop = NULL;
840 monitor->jobs = ply_hashtable_new (ply_hashtable_string_hash,
841 ply_hashtable_string_compare);
842 monitor->all_instances = ply_hashtable_new (ply_hashtable_string_hash,
843 ply_hashtable_string_compare);
844 monitor->state_changed_handler = NULL;
845 monitor->state_changed_data = NULL;
846 monitor->failed_handler = NULL;
847 monitor->failed_data = NULL;
848 monitor->dispatch_fd = -1;
849
850 if (!dbus_connection_add_filter (connection, message_handler, monitor, NULL))
851 {
852 ply_error ("unable to add filter to system bus connection");
853 ply_upstart_monitor_free (monitor);
854 return NULL;
855 }
856
857 ply_trace ("calling GetAllJobs");
858 message = dbus_message_new_method_call (UPSTART_SERVICE, UPSTART_PATH,
859 UPSTART_INTERFACE_0_6,
860 "GetAllJobs");
861 dbus_connection_send_with_reply (monitor->connection, message, &call, -1);
862 dbus_message_unref (message);
863 if (call != NULL)
864 dbus_pending_call_set_notify (call,
865 (DBusPendingCallNotifyFunction)
866 on_get_all_jobs_finished,
867 monitor, NULL);
868
869 if (loop != NULL)
870 ply_upstart_monitor_connect_to_event_loop (monitor, loop);
871
872 return monitor;
873}
874
875void
876ply_upstart_monitor_free (ply_upstart_monitor_t *monitor)
877{
878 if (monitor == NULL)
879 return;
880
881 ply_hashtable_free (monitor->all_instances);
882 ply_hashtable_free (monitor->jobs);
883 dbus_connection_unref (monitor->connection);
884 if (monitor->dispatch_fd >= 0)
885 close (monitor->dispatch_fd);
886 free (monitor);
887}
888
889static void
890read_watch_handler (void *data, int fd)
891{
892 DBusWatch *watch = data;
893
894 assert (watch != NULL);
895
896 dbus_watch_handle (watch, DBUS_WATCH_READABLE);
897}
898
899static void
900write_watch_handler (void *data, int fd)
901{
902 DBusWatch *watch = data;
903
904 assert (watch != NULL);
905
906 dbus_watch_handle (watch, DBUS_WATCH_WRITABLE);
907}
908
909static dbus_bool_t
910add_watch (DBusWatch *watch, void *data)
911{
912 ply_upstart_monitor_t *monitor = data;
913 unsigned int flags;
914 int fd;
915 ply_event_loop_fd_status_t status;
916 ply_fd_watch_t *read_watch_event = NULL, *write_watch_event = NULL;
917
918 assert (monitor != NULL);
919 assert (watch != NULL);
920
921 if (!dbus_watch_get_enabled (watch))
922 return TRUE;
923
924 assert (dbus_watch_get_data (watch) == NULL);
925
926 flags = dbus_watch_get_flags (watch);
927 fd = dbus_watch_get_unix_fd (watch);
928
929 if (flags & DBUS_WATCH_READABLE)
930 {
931 status = PLY_EVENT_LOOP_FD_STATUS_HAS_DATA;
932 read_watch_event = ply_event_loop_watch_fd (monitor->loop, fd, status,
933 read_watch_handler, NULL,
934 watch);
935 if (read_watch_event == NULL)
936 return FALSE;
937 dbus_watch_set_data (watch, read_watch_event, NULL);
938 }
939
940 if (flags & DBUS_WATCH_WRITABLE)
941 {
942 status = PLY_EVENT_LOOP_FD_STATUS_CAN_TAKE_DATA;
943 write_watch_event = ply_event_loop_watch_fd (monitor->loop, fd, status,
944 write_watch_handler, NULL,
945 watch);
946 if (write_watch_event == NULL)
947 {
948 if (read_watch_event != NULL)
949 ply_event_loop_stop_watching_fd (monitor->loop, read_watch_event);
950 return FALSE;
951 }
952 dbus_watch_set_data (watch, write_watch_event, NULL);
953 }
954
955 return TRUE;
956}
957
958static void
959remove_watch (DBusWatch *watch, void *data)
960{
961 ply_upstart_monitor_t *monitor = data;
962 ply_fd_watch_t *watch_event;
963
964 assert (monitor != NULL);
965 assert (watch != NULL);
966
967 watch_event = dbus_watch_get_data (watch);
968 if (watch_event == NULL)
969 return;
970
971 ply_event_loop_stop_watching_fd (monitor->loop, watch_event);
972
973 dbus_watch_set_data (watch, NULL, NULL);
974}
975
976static void
977toggled_watch (DBusWatch *watch, void *data)
978{
979 if (dbus_watch_get_enabled (watch))
980 add_watch (watch, data);
981 else
982 remove_watch (watch, data);
983}
984
985static ply_upstart_monitor_timeout_t *
986timeout_user_data_new (ply_upstart_monitor_t *monitor, DBusTimeout *timeout)
987{
988 ply_upstart_monitor_timeout_t *monitor_timeout;
989
990 monitor_timeout = calloc (1, sizeof (ply_upstart_monitor_timeout_t));
991 monitor_timeout->monitor = monitor;
992 monitor_timeout->timeout = timeout;
993
994 return monitor_timeout;
995}
996
997static void
998timeout_user_data_free (void *data)
999{
1000 ply_upstart_monitor_timeout_t *monitor_timeout = data;
1001
1002 free (monitor_timeout);
1003}
1004
1005static void
1006timeout_handler (void *data, ply_event_loop_t *loop)
1007{
1008 ply_upstart_monitor_timeout_t *monitor_timeout = data;
1009
1010 assert (monitor_timeout != NULL);
1011
1012 dbus_timeout_handle (monitor_timeout->timeout);
1013}
1014
1015static dbus_bool_t
1016add_timeout (DBusTimeout *timeout, void *data)
1017{
1018 ply_upstart_monitor_t *monitor = data;
1019 int interval;
1020 ply_upstart_monitor_timeout_t *monitor_timeout;
1021
1022 assert (monitor != NULL);
1023 assert (timeout != NULL);
1024
1025 if (!dbus_timeout_get_enabled (timeout))
1026 return TRUE;
1027
1028 interval = dbus_timeout_get_interval (timeout) * 1000;
1029
1030 monitor_timeout = timeout_user_data_new (monitor, timeout);
1031
1032 ply_event_loop_watch_for_timeout (monitor->loop, (double) interval,
1033 timeout_handler, monitor_timeout);
1034
1035 dbus_timeout_set_data (timeout, monitor_timeout, timeout_user_data_free);
1036
1037 return TRUE;
1038}
1039
1040static void
1041remove_timeout (DBusTimeout *timeout, void *data)
1042{
1043 ply_upstart_monitor_t *monitor = data;
1044 ply_upstart_monitor_timeout_t *monitor_timeout;
1045
1046 assert (monitor != NULL);
1047 assert (timeout != NULL);
1048
1049 monitor_timeout = dbus_timeout_get_data (timeout);
1050 if (monitor_timeout == NULL)
1051 return;
1052
1053 ply_event_loop_stop_watching_for_timeout (monitor->loop,
1054 timeout_handler, monitor_timeout);
1055
1056 dbus_timeout_set_data (timeout, NULL, NULL);
1057}
1058
1059static void
1060toggled_timeout (DBusTimeout *timeout, void *data)
1061{
1062 if (dbus_timeout_get_enabled (timeout))
1063 add_timeout (timeout, data);
1064 else
1065 remove_timeout (timeout, data);
1066}
1067
1068static void
1069dispatch_status (DBusConnection *connection, DBusDispatchStatus new_status,
1070 void *data)
1071{
1072 ply_upstart_monitor_t *monitor = data;
1073 uint64_t event_payload;
1074
1075 assert (monitor != NULL);
1076
1077 if (new_status != DBUS_DISPATCH_DATA_REMAINS)
1078 return;
1079
1080 /* wake up event loop */
1081 event_payload = 1;
1082 ply_write (monitor->dispatch_fd, &event_payload, sizeof (event_payload));
1083}
1084
1085static void
1086dispatch (void *data, int fd)
1087{
1088 ply_upstart_monitor_t *monitor = data;
1089 uint64_t event_payload;
1090
1091 assert (monitor != NULL);
1092
1093 /* reset eventfd to zero */
1094 ply_read (fd, &event_payload, sizeof (event_payload));
1095
1096 while (dbus_connection_dispatch (monitor->connection) ==
1097 DBUS_DISPATCH_DATA_REMAINS)
1098 ;
1099}
1100
1101bool
1102ply_upstart_monitor_connect_to_event_loop (ply_upstart_monitor_t *monitor,
1103 ply_event_loop_t *loop)
1104{
1105 ply_fd_watch_t *dispatch_event = NULL;
1106 uint64_t event_payload;
1107
1108 assert (monitor != NULL);
1109
1110 monitor->loop = loop;
1111 monitor->dispatch_fd = -1;
1112
1113 if (!dbus_connection_set_watch_functions (monitor->connection,
1114 add_watch,
1115 remove_watch,
1116 toggled_watch,
1117 monitor, NULL))
1118 goto err;
1119
1120 if (!dbus_connection_set_timeout_functions (monitor->connection,
1121 add_timeout,
1122 remove_timeout,
1123 toggled_timeout,
1124 monitor, NULL))
1125 goto err;
1126
1127 monitor->dispatch_fd = eventfd (0, EFD_CLOEXEC | EFD_NONBLOCK);
1128 if (monitor->dispatch_fd < 0)
1129 goto err;
1130 /* make sure we wake up to dispatch the first time through */
1131 event_payload = 1;
1132 ply_write (monitor->dispatch_fd, &event_payload, sizeof (event_payload));
1133
1134 dispatch_event = ply_event_loop_watch_fd (monitor->loop,
1135 monitor->dispatch_fd,
1136 PLY_EVENT_LOOP_FD_STATUS_HAS_DATA,
1137 dispatch, NULL, monitor);
1138 if (dispatch_event == NULL)
1139 goto err;
1140
1141 dbus_connection_set_dispatch_status_function (monitor->connection,
1142 dispatch_status,
1143 monitor, NULL);
1144
1145 return true;
1146
1147err:
1148 dbus_connection_set_watch_functions (monitor->connection,
1149 NULL, NULL, NULL, NULL, NULL);
1150 dbus_connection_set_timeout_functions (monitor->connection,
1151 NULL, NULL, NULL, NULL, NULL);
1152 dbus_connection_set_dispatch_status_function (monitor->connection,
1153 NULL, NULL, NULL);
1154 if (dispatch_event != NULL)
1155 ply_event_loop_stop_watching_fd (monitor->loop, dispatch_event);
1156 if (monitor->dispatch_fd >= 0)
1157 {
1158 close (monitor->dispatch_fd);
1159 monitor->dispatch_fd = -1;
1160 }
1161 monitor->loop = NULL;
1162 return false;
1163}
1164
1165void
1166ply_upstart_monitor_add_state_changed_handler (ply_upstart_monitor_t *monitor,
1167 ply_upstart_monitor_state_changed_handler_t handler,
1168 void *user_data)
1169{
1170 monitor->state_changed_handler = handler;
1171 monitor->state_changed_data = user_data;
1172}
1173
1174void
1175ply_upstart_monitor_add_failed_handler (ply_upstart_monitor_t *monitor,
1176 ply_upstart_monitor_failed_handler_t handler,
1177 void *user_data)
1178{
1179 monitor->failed_handler = handler;
1180 monitor->failed_data = user_data;
1181}
1182/* vim: set ts=4 sw=4 expandtab autoindent cindent cino={.5s,(0: */
01183
=== added directory '.pc/ubuntu-logo-scale-factor-2.patch'
=== added directory '.pc/ubuntu-logo-scale-factor-2.patch/themes'
=== added directory '.pc/ubuntu-logo-scale-factor-2.patch/themes/ubuntu-logo'
=== added file '.pc/ubuntu-logo-scale-factor-2.patch/themes/ubuntu-logo/Makefile.am'
--- .pc/ubuntu-logo-scale-factor-2.patch/themes/ubuntu-logo/Makefile.am 1970-01-01 00:00:00 +0000
+++ .pc/ubuntu-logo-scale-factor-2.patch/themes/ubuntu-logo/Makefile.am 2014-03-14 10:43:52 +0000
@@ -0,0 +1,23 @@
1themedir = $(datadir)/plymouth/themes/ubuntu-logo
2nodist_theme_DATA = ubuntu-logo.plymouth
3dist_theme_DATA = ubuntu-logo.script \
4 ubuntu-logo.grub \
5 ubuntu_logo.png \
6 ubuntu_logo16.png \
7 password_field.png \
8 password_field16.png \
9 progress_dot_off.png \
10 progress_dot_off16.png \
11 progress_dot_on.png \
12 progress_dot_on16.png
13
14
15
16MAINTAINERCLEANFILES = Makefile.in ubuntu-logo.plymouth
17CLEANFILES = ubuntu-logo.plymouth
18
19ubuntu-logo.plymouth: $(srcdir)/ubuntu-logo.plymouth.in
20 sed -e 's,[@]PLYMOUTH_THEME_PATH[@],$(PLYMOUTH_THEME_PATH),g' \
21 $(srcdir)/ubuntu-logo.plymouth.in > ubuntu-logo.plymouth
22
23EXTRA_DIST = ubuntu-logo.plymouth.in
024
=== added file '.pc/ubuntu-logo-scale-factor-2.patch/themes/ubuntu-logo/ubuntu-logo.plymouth.in'
--- .pc/ubuntu-logo-scale-factor-2.patch/themes/ubuntu-logo/ubuntu-logo.plymouth.in 1970-01-01 00:00:00 +0000
+++ .pc/ubuntu-logo-scale-factor-2.patch/themes/ubuntu-logo/ubuntu-logo.plymouth.in 2014-03-14 10:43:52 +0000
@@ -0,0 +1,8 @@
1[Plymouth Theme]
2Name=Ubuntu Logo
3Description=A theme that features a blank background with a logo.
4ModuleName=script
5
6[script]
7ImageDir=@PLYMOUTH_THEME_PATH@/ubuntu-logo
8ScriptFile=@PLYMOUTH_THEME_PATH@/ubuntu-logo/ubuntu-logo.script
09
=== added file '.pc/ubuntu-logo-scale-factor-2.patch/themes/ubuntu-logo/ubuntu-logo.script.in'
=== added directory '.pc/use-upstart-private-socket.patch'
=== added directory '.pc/use-upstart-private-socket.patch/src'
=== added directory '.pc/use-upstart-private-socket.patch/src/upstart-bridge'
=== added file '.pc/use-upstart-private-socket.patch/src/upstart-bridge/ply-upstart-monitor.c'
--- .pc/use-upstart-private-socket.patch/src/upstart-bridge/ply-upstart-monitor.c 1970-01-01 00:00:00 +0000
+++ .pc/use-upstart-private-socket.patch/src/upstart-bridge/ply-upstart-monitor.c 2014-03-14 10:43:52 +0000
@@ -0,0 +1,1301 @@
1/* ply-upstart-monitor.c - Upstart D-Bus monitor
2 *
3 * Copyright (C) 2010, 2011 Canonical Ltd.
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2, or (at your option)
8 * any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
18 * 02111-1307, USA.
19 *
20 * Written by: Colin Watson <cjwatson@ubuntu.com>
21 */
22#include "config.h"
23#include "ply-upstart-monitor.h"
24
25#include <assert.h>
26#include <stdbool.h>
27#include <stdlib.h>
28#include <stdio.h>
29#include <string.h>
30#include <sys/eventfd.h>
31
32#include <dbus/dbus.h>
33
34#include "ply-logger.h"
35#include "ply-event-loop.h"
36#include "ply-hashtable.h"
37#include "ply-list.h"
38#include "ply-utils.h"
39
40typedef struct
41{
42 ply_upstart_monitor_t *monitor;
43 DBusTimeout *timeout;
44} ply_upstart_monitor_timeout_t;
45
46struct _ply_upstart_monitor
47{
48 DBusConnection *connection;
49 char *owner;
50 ply_event_loop_t *loop;
51 ply_hashtable_t *jobs;
52 ply_hashtable_t *all_instances;
53 ply_upstart_monitor_state_changed_handler_t state_changed_handler;
54 void *state_changed_data;
55 ply_upstart_monitor_failed_handler_t failed_handler;
56 void *failed_data;
57 int dispatch_fd;
58};
59
60typedef struct
61{
62 ply_upstart_monitor_t *monitor;
63 ply_upstart_monitor_job_properties_t properties;
64 ply_hashtable_t *instances;
65 ply_list_t *pending_calls;
66} ply_upstart_monitor_job_t;
67
68typedef struct
69{
70 ply_upstart_monitor_job_t *job;
71 ply_upstart_monitor_instance_properties_t properties;
72 ply_list_t *pending_calls;
73 uint32_t state_changed : 1;
74 uint32_t call_failed : 1;
75} ply_upstart_monitor_instance_t;
76
77#define UPSTART_SERVICE "com.ubuntu.Upstart"
78#define UPSTART_PATH "/com/ubuntu/Upstart"
79#define UPSTART_INTERFACE_0_6 "com.ubuntu.Upstart0_6"
80#define UPSTART_INTERFACE_0_6_JOB "com.ubuntu.Upstart0_6.Job"
81#define UPSTART_INTERFACE_0_6_INSTANCE "com.ubuntu.Upstart0_6.Instance"
82
83/* Remove an entry from a hashtable, free the key, and return the data. */
84static void *
85hashtable_remove_and_free_key (ply_hashtable_t *hashtable,
86 const void *key)
87{
88 void *reply_key, *reply_data;
89
90 if (!ply_hashtable_lookup_full (hashtable, (void *) key,
91 &reply_key, &reply_data))
92 return NULL;
93 ply_hashtable_remove (hashtable, (void *) key);
94 free (reply_key);
95
96 return reply_data;
97}
98
99/* We assume, in general, that Upstart responds to D-Bus messages in a
100 * single thread, and that it processes messages on a given connection in
101 * the order in which they were sent. Taken together, these assumptions
102 * imply a kind of coherence: a Properties.GetAll reply received after a
103 * StateChanged signal must have been computed entirely after the state
104 * change. Thus, if this function returns false (properties have not been
105 * fetched yet), it should be safe to record an event as call until such
106 * time as the properties of the instance are known.
107 */
108static bool
109instance_is_initialized (ply_upstart_monitor_instance_t *instance)
110{
111 /* Note that the job may not have a description. */
112 if (instance->job->properties.name &&
113 instance->properties.name && instance->properties.goal &&
114 instance->properties.state)
115 return true;
116 else
117 return false;
118}
119
120static void
121on_get_all_instance_properties_finished (DBusPendingCall *call,
122 ply_upstart_monitor_instance_t *instance)
123{
124 DBusMessage *reply;
125 DBusMessageIter iter, array_iter, dict_iter, variant_iter;
126 const char *key, *name, *goal, *state;
127 ply_upstart_monitor_t *monitor;
128
129 assert (call != NULL);
130 assert (instance != NULL);
131
132 reply = dbus_pending_call_steal_reply (call);
133 if (reply == NULL)
134 return;
135 if (dbus_message_get_type (reply) != DBUS_MESSAGE_TYPE_METHOD_RETURN)
136 goto out;
137
138 dbus_message_iter_init (reply, &iter);
139 if (dbus_message_iter_get_arg_type (&iter) != DBUS_TYPE_ARRAY)
140 goto out;
141 dbus_message_iter_recurse (&iter, &array_iter);
142
143 while (dbus_message_iter_get_arg_type (&array_iter) == DBUS_TYPE_DICT_ENTRY)
144 {
145 dbus_message_iter_recurse (&array_iter, &dict_iter);
146
147 if (dbus_message_iter_get_arg_type (&dict_iter) != DBUS_TYPE_STRING)
148 goto next_item;
149
150 dbus_message_iter_get_basic (&dict_iter, &key);
151 if (key == NULL)
152 goto next_item;
153
154 dbus_message_iter_next (&dict_iter);
155 if (dbus_message_iter_get_arg_type (&dict_iter) != DBUS_TYPE_VARIANT)
156 goto next_item;
157 dbus_message_iter_recurse (&dict_iter, &variant_iter);
158 if (dbus_message_iter_get_arg_type (&variant_iter) != DBUS_TYPE_STRING)
159 goto next_item;
160
161 if (strcmp (key, "name") == 0)
162 {
163 dbus_message_iter_get_basic (&variant_iter, &name);
164 if (name != NULL)
165 {
166 ply_trace ("%s: name = '%s'",
167 instance->job->properties.name, name);
168 instance->properties.name = strdup (name);
169 }
170 }
171 else if (strcmp (key, "goal") == 0)
172 {
173 dbus_message_iter_get_basic (&variant_iter, &goal);
174 if (goal != NULL)
175 {
176 ply_trace ("%s: goal = '%s'",
177 instance->job->properties.name, goal);
178 instance->properties.goal = strdup (goal);
179 }
180 }
181 else if (strcmp (key, "state") == 0)
182 {
183 dbus_message_iter_get_basic (&variant_iter, &state);
184 if (state != NULL)
185 {
186 ply_trace ("%s: state = '%s'",
187 instance->job->properties.name, state);
188 instance->properties.state = strdup (state);
189 }
190 }
191
192next_item:
193 dbus_message_iter_next (&array_iter);
194 }
195
196out:
197 dbus_message_unref (reply);
198
199 if (instance_is_initialized (instance))
200 {
201 /* Process any call events. */
202 monitor = instance->job->monitor;
203
204 if (instance->state_changed && monitor->state_changed_handler)
205 monitor->state_changed_handler (monitor->state_changed_data, NULL,
206 &instance->job->properties,
207 &instance->properties);
208 instance->state_changed = false;
209
210 if (instance->call_failed && monitor->failed_handler)
211 monitor->failed_handler (monitor->failed_data,
212 &instance->job->properties,
213 &instance->properties,
214 instance->properties.failed);
215 instance->call_failed = false;
216 }
217}
218
219static void
220on_get_all_job_properties_finished (DBusPendingCall *call,
221 ply_upstart_monitor_job_t *job)
222{
223 DBusMessage *reply;
224 DBusMessageIter iter, array_iter, dict_iter, variant_iter;
225 const char *key, *name, *description;
226 dbus_uint32_t task;
227
228 assert (call != NULL);
229 assert (job != NULL);
230
231 reply = dbus_pending_call_steal_reply (call);
232 if (reply == NULL)
233 return;
234 if (dbus_message_get_type (reply) != DBUS_MESSAGE_TYPE_METHOD_RETURN)
235 goto out;
236
237 dbus_message_iter_init (reply, &iter);
238 if (dbus_message_iter_get_arg_type (&iter) != DBUS_TYPE_ARRAY)
239 goto out;
240 dbus_message_iter_recurse (&iter, &array_iter);
241
242 while (dbus_message_iter_get_arg_type (&array_iter) == DBUS_TYPE_DICT_ENTRY)
243 {
244 dbus_message_iter_recurse (&array_iter, &dict_iter);
245
246 if (dbus_message_iter_get_arg_type (&dict_iter) != DBUS_TYPE_STRING)
247 goto next_item;
248
249 dbus_message_iter_get_basic (&dict_iter, &key);
250 if (key == NULL)
251 goto next_item;
252
253 dbus_message_iter_next (&dict_iter);
254 if (dbus_message_iter_get_arg_type (&dict_iter) != DBUS_TYPE_VARIANT)
255 goto next_item;
256 dbus_message_iter_recurse (&dict_iter, &variant_iter);
257
258 if (strcmp (key, "name") == 0)
259 {
260 if (dbus_message_iter_get_arg_type (&variant_iter) !=
261 DBUS_TYPE_STRING)
262 goto next_item;
263 dbus_message_iter_get_basic (&variant_iter, &name);
264 if (name != NULL)
265 {
266 ply_trace ("name = '%s'", name);
267 job->properties.name = strdup (name);
268 }
269 }
270 else if (strcmp (key, "description") == 0)
271 {
272 if (dbus_message_iter_get_arg_type (&variant_iter) !=
273 DBUS_TYPE_STRING)
274 goto next_item;
275 dbus_message_iter_get_basic (&variant_iter, &description);
276 if (description != NULL)
277 {
278 ply_trace ("description = '%s'", description);
279 job->properties.description = strdup (description);
280 }
281 }
282 else if (strcmp (key, "task") == 0)
283 {
284 if (dbus_message_iter_get_arg_type (&variant_iter) !=
285 DBUS_TYPE_BOOLEAN)
286 goto next_item;
287 dbus_message_iter_get_basic (&variant_iter, &task);
288 ply_trace ("task = %s", task ? "TRUE" : "FALSE");
289 job->properties.is_task = task ? true : false;
290 }
291
292next_item:
293 dbus_message_iter_next (&array_iter);
294 }
295
296out:
297 dbus_message_unref (reply);
298}
299
300static void
301remove_instance_internal (ply_upstart_monitor_job_t *job, const char *path)
302{
303 ply_upstart_monitor_instance_t *instance;
304 ply_list_node_t *node;
305
306 instance = hashtable_remove_and_free_key (job->instances, path);
307 if (instance == NULL)
308 return;
309 hashtable_remove_and_free_key (job->monitor->all_instances, path);
310
311 node = ply_list_get_first_node (instance->pending_calls);
312 while (node != NULL)
313 {
314 DBusPendingCall *call;
315 ply_list_node_t *next_node;
316
317 call = ply_list_node_get_data (node);
318 next_node = ply_list_get_next_node (instance->pending_calls, node);
319 dbus_pending_call_cancel (call);
320 dbus_pending_call_unref (call);
321 node = next_node;
322 }
323 ply_list_free (instance->pending_calls);
324
325 free (instance->properties.name);
326 free (instance->properties.goal);
327 free (instance->properties.state);
328 free (instance);
329}
330
331static void
332add_instance (ply_upstart_monitor_job_t *job,
333 const char *path)
334{
335 ply_upstart_monitor_instance_t *instance;
336 DBusMessage *message;
337 const char *interface = UPSTART_INTERFACE_0_6_INSTANCE;
338 DBusPendingCall *call;
339
340 ply_trace ("adding instance: %s", path);
341
342 remove_instance_internal (job, path);
343
344 instance = calloc (1, sizeof (ply_upstart_monitor_instance_t));
345 instance->job = job;
346 instance->properties.name = NULL;
347 instance->properties.goal = NULL;
348 instance->properties.state = NULL;
349 instance->properties.failed = false;
350 instance->pending_calls = ply_list_new ();
351 instance->state_changed = false;
352 instance->call_failed = false;
353
354 /* Keep a hash of instances per job, to make InstanceRemoved handling
355 * easy.
356 */
357 ply_hashtable_insert (job->instances, strdup (path), instance);
358 /* Keep a separate hash of all instances, to make StateChanged handling
359 * easy.
360 */
361 ply_hashtable_insert (job->monitor->all_instances, strdup (path), instance);
362
363 /* Ask Upstart for the name, goal, and state properties. */
364 ply_trace ("fetching properties of instance %s", path);
365 message = dbus_message_new_method_call (UPSTART_SERVICE, path,
366 DBUS_INTERFACE_PROPERTIES, "GetAll");
367 dbus_message_append_args (message,
368 DBUS_TYPE_STRING, &interface,
369 DBUS_TYPE_INVALID);
370 dbus_connection_send_with_reply (job->monitor->connection, message,
371 &call, -1);
372 dbus_message_unref (message);
373 if (call != NULL)
374 {
375 dbus_pending_call_set_notify (call,
376 (DBusPendingCallNotifyFunction)
377 on_get_all_instance_properties_finished,
378 instance, NULL);
379 ply_list_append_data (instance->pending_calls, call);
380 }
381}
382
383static void
384remove_instance (ply_upstart_monitor_job_t *job,
385 const char *path)
386{
387 ply_trace ("removing instance: %s", path);
388
389 remove_instance_internal (job, path);
390}
391
392static void
393on_get_all_instances_finished (DBusPendingCall *call,
394 ply_upstart_monitor_job_t *job)
395{
396 DBusMessage *reply;
397 DBusError error;
398 char **instances;
399 int n_instances, i;
400
401 assert (call != NULL);
402 assert (job != NULL);
403
404 reply = dbus_pending_call_steal_reply (call);
405 if (reply == NULL)
406 return;
407 if (dbus_message_get_type (reply) != DBUS_MESSAGE_TYPE_METHOD_RETURN)
408 goto out;
409
410 dbus_error_init (&error);
411 dbus_message_get_args (reply, &error,
412 DBUS_TYPE_ARRAY, DBUS_TYPE_OBJECT_PATH,
413 &instances, &n_instances,
414 DBUS_TYPE_INVALID);
415 if (dbus_error_is_set (&error))
416 goto out;
417 dbus_error_free (&error);
418
419 for (i = 0; i < n_instances; ++i)
420 add_instance (job, instances[i]);
421
422 dbus_free_string_array (instances);
423
424out:
425 dbus_message_unref (reply);
426}
427
428static void
429free_job_instance (void *key, void *data, void *user_data)
430{
431 const char *path = key;
432 ply_upstart_monitor_instance_t *instance = data;
433 ply_upstart_monitor_t *monitor = user_data;
434
435 assert (monitor != NULL);
436
437 if (instance == NULL)
438 return;
439
440 hashtable_remove_and_free_key (monitor->all_instances, path);
441 free (instance->properties.name);
442 free (instance->properties.goal);
443 free (instance->properties.state);
444 free (instance);
445}
446
447static void
448remove_job_internal (ply_upstart_monitor_t *monitor, const char *path)
449{
450 ply_upstart_monitor_job_t *job;
451 ply_list_node_t *node;
452
453 job = hashtable_remove_and_free_key (monitor->jobs, path);
454 if (job == NULL)
455 return;
456
457 node = ply_list_get_first_node (job->pending_calls);
458 while (node != NULL)
459 {
460 DBusPendingCall *call;
461 ply_list_node_t *next_node;
462
463 call = ply_list_node_get_data (node);
464 next_node = ply_list_get_next_node (job->pending_calls, node);
465 dbus_pending_call_cancel (call);
466 dbus_pending_call_unref (call);
467 node = next_node;
468 }
469 ply_list_free (job->pending_calls);
470
471 free (job->properties.name);
472 free (job->properties.description);
473 ply_hashtable_foreach (job->instances, free_job_instance, monitor);
474 ply_hashtable_free (job->instances);
475 free (job);
476}
477
478static void
479add_job (ply_upstart_monitor_t *monitor, const char *path)
480{
481 ply_upstart_monitor_job_t *job;
482 DBusMessage *message;
483 const char *interface = UPSTART_INTERFACE_0_6_JOB;
484 DBusPendingCall *call;
485
486 ply_trace ("adding job: %s", path);
487
488 remove_job_internal (monitor, path);
489
490 job = calloc (1, sizeof (ply_upstart_monitor_job_t));
491 job->monitor = monitor;
492 job->properties.name = NULL;
493 job->properties.description = NULL;
494 job->properties.is_task = false;
495 job->instances = ply_hashtable_new (ply_hashtable_string_hash,
496 ply_hashtable_string_compare);
497 job->pending_calls = ply_list_new ();
498
499 ply_hashtable_insert (monitor->jobs, strdup (path), job);
500
501 /* Ask Upstart for the name and description properties. */
502 ply_trace ("fetching properties of job %s", path);
503 message = dbus_message_new_method_call (UPSTART_SERVICE, path,
504 DBUS_INTERFACE_PROPERTIES, "GetAll");
505 dbus_message_append_args (message,
506 DBUS_TYPE_STRING, &interface,
507 DBUS_TYPE_INVALID);
508 dbus_connection_send_with_reply (monitor->connection, message, &call, -1);
509 dbus_message_unref (message);
510 if (call != NULL)
511 {
512 dbus_pending_call_set_notify (call,
513 (DBusPendingCallNotifyFunction)
514 on_get_all_job_properties_finished,
515 job,
516 NULL);
517 ply_list_append_data (job->pending_calls, call);
518 }
519
520 /* Ask Upstart for a list of all instances of this job. */
521 ply_trace ("calling GetAllInstances on job %s", path);
522 message = dbus_message_new_method_call (UPSTART_SERVICE, path,
523 UPSTART_INTERFACE_0_6_JOB,
524 "GetAllInstances");
525 dbus_connection_send_with_reply (monitor->connection, message, &call, -1);
526 dbus_message_unref (message);
527 if (call != NULL)
528 {
529 dbus_pending_call_set_notify (call,
530 (DBusPendingCallNotifyFunction)
531 on_get_all_instances_finished,
532 job,
533 NULL);
534 ply_list_append_data (job->pending_calls, call);
535 }
536}
537
538static void
539remove_job (ply_upstart_monitor_t *monitor, const char *path)
540{
541 ply_trace ("removing job: %s", path);
542
543 remove_job_internal (monitor, path);
544}
545
546static void
547on_get_all_jobs_finished (DBusPendingCall *call,
548 ply_upstart_monitor_t *monitor)
549{
550 DBusMessage *reply;
551 DBusError error;
552 char **jobs;
553 int n_jobs, i;
554
555 assert (call != NULL);
556 assert (monitor != NULL);
557
558 reply = dbus_pending_call_steal_reply (call);
559 if (reply == NULL)
560 return;
561 if (dbus_message_get_type (reply) != DBUS_MESSAGE_TYPE_METHOD_RETURN)
562 goto out;
563
564 dbus_error_init (&error);
565 dbus_message_get_args (reply, &error,
566 DBUS_TYPE_ARRAY, DBUS_TYPE_OBJECT_PATH,
567 &jobs, &n_jobs,
568 DBUS_TYPE_INVALID);
569 if (dbus_error_is_set (&error))
570 goto out;
571 dbus_error_free (&error);
572
573 for (i = 0; i < n_jobs; ++i)
574 add_job (monitor, jobs[i]);
575
576 dbus_free_string_array (jobs);
577
578out:
579 dbus_message_unref (reply);
580}
581
582static void
583on_get_name_owner_finished (DBusPendingCall *call,
584 ply_upstart_monitor_t *monitor)
585{
586 DBusMessage *reply, *message;
587 DBusError error;
588 const char *owner;
589
590 assert (call != NULL);
591 assert (monitor != NULL);
592
593 reply = dbus_pending_call_steal_reply (call);
594 if (reply == NULL)
595 return;
596 if (dbus_message_get_type (reply) != DBUS_MESSAGE_TYPE_METHOD_RETURN)
597 goto out;
598
599 dbus_error_init (&error);
600 dbus_message_get_args (reply, &error,
601 DBUS_TYPE_STRING, &owner,
602 DBUS_TYPE_INVALID);
603 if (dbus_error_is_set (&error))
604 goto out;
605 dbus_error_free (&error);
606
607 ply_trace ("owner = '%s'", owner);
608
609 free (monitor->owner);
610 monitor->owner = strdup (owner);
611
612 ply_trace ("calling GetAllJobs");
613 message = dbus_message_new_method_call (UPSTART_SERVICE, UPSTART_PATH,
614 UPSTART_INTERFACE_0_6,
615 "GetAllJobs");
616 dbus_connection_send_with_reply (monitor->connection, message, &call, -1);
617 dbus_message_unref (message);
618 if (call != NULL)
619 dbus_pending_call_set_notify (call,
620 (DBusPendingCallNotifyFunction)
621 on_get_all_jobs_finished,
622 monitor, NULL);
623
624out:
625 dbus_message_unref (reply);
626}
627
628static DBusHandlerResult
629name_owner_changed_handler (DBusConnection *connection,
630 DBusMessage *message,
631 ply_upstart_monitor_t *monitor)
632{
633 DBusError error;
634 const char *name, *old_owner, *new_owner;
635
636 assert (connection != NULL);
637 assert (message != NULL);
638 assert (monitor != NULL);
639
640 dbus_error_init (&error);
641 if (dbus_message_get_args (message, &error,
642 DBUS_TYPE_STRING, &name,
643 DBUS_TYPE_STRING, &old_owner,
644 DBUS_TYPE_STRING, &new_owner,
645 DBUS_TYPE_INVALID) &&
646 strcmp (name, UPSTART_SERVICE) == 0)
647 {
648 if (new_owner)
649 ply_trace ("owner changed from '%s' to '%s'", old_owner, new_owner);
650 else
651 ply_trace ("owner left bus");
652 free (monitor->owner);
653 monitor->owner = new_owner ? strdup (new_owner) : NULL;
654 }
655
656 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; /* let other handlers try */
657}
658
659static DBusHandlerResult
660job_added_handler (DBusConnection *connection,
661 DBusMessage *message,
662 ply_upstart_monitor_t *monitor)
663{
664 DBusError error;
665 const char *signal_path;
666
667 ply_trace ("got JobAdded");
668 dbus_error_init (&error);
669 if (dbus_message_get_args (message, &error,
670 DBUS_TYPE_OBJECT_PATH, &signal_path,
671 DBUS_TYPE_INVALID))
672 add_job (monitor, signal_path);
673 dbus_error_free (&error);
674 return DBUS_HANDLER_RESULT_HANDLED;
675}
676
677static DBusHandlerResult
678job_removed_handler (DBusConnection *connection,
679 DBusMessage *message,
680 ply_upstart_monitor_t *monitor)
681{
682 DBusError error;
683 const char *signal_path;
684
685 ply_trace ("got JobRemoved");
686 dbus_error_init (&error);
687 if (dbus_message_get_args (message, &error,
688 DBUS_TYPE_OBJECT_PATH, &signal_path,
689 DBUS_TYPE_INVALID))
690 remove_job (monitor, signal_path);
691 dbus_error_free (&error);
692 return DBUS_HANDLER_RESULT_HANDLED;
693}
694
695static DBusHandlerResult
696instance_added_handler (DBusConnection *connection, DBusMessage *message,
697 ply_upstart_monitor_t *monitor, const char *path)
698{
699 DBusError error;
700 const char *signal_path;
701 ply_upstart_monitor_job_t *job;
702
703 ply_trace ("got %s InstanceAdded", path);
704 job = ply_hashtable_lookup (monitor->jobs, (void *) path);
705 if (job != NULL)
706 {
707 dbus_error_init (&error);
708 if (dbus_message_get_args (message, &error,
709 DBUS_TYPE_OBJECT_PATH, &signal_path,
710 DBUS_TYPE_INVALID))
711 add_instance (job, signal_path);
712 dbus_error_free (&error);
713 }
714 return DBUS_HANDLER_RESULT_HANDLED;
715}
716
717static DBusHandlerResult
718instance_removed_handler (DBusConnection *connection, DBusMessage *message,
719 ply_upstart_monitor_t *monitor, const char *path)
720{
721 DBusError error;
722 const char *signal_path;
723 ply_upstart_monitor_job_t *job;
724
725 ply_trace ("got %s InstanceRemoved", path);
726 job = ply_hashtable_lookup (monitor->jobs, (void *) path);
727 if (job != NULL)
728 {
729 dbus_error_init (&error);
730 if (dbus_message_get_args (message, &error,
731 DBUS_TYPE_OBJECT_PATH, &signal_path,
732 DBUS_TYPE_INVALID))
733 remove_instance (job, signal_path);
734 dbus_error_free (&error);
735 }
736 return DBUS_HANDLER_RESULT_HANDLED;
737}
738
739static DBusHandlerResult
740goal_changed_handler (DBusConnection *connection, DBusMessage *message,
741 ply_upstart_monitor_t *monitor, const char *path)
742{
743 DBusError error;
744 const char *goal;
745 ply_upstart_monitor_instance_t *instance;
746 char *old_goal;
747
748 ply_trace ("got %s GoalChanged", path);
749 instance = ply_hashtable_lookup (monitor->all_instances, (void *) path);
750 if (instance != NULL)
751 {
752 dbus_error_init (&error);
753 if (dbus_message_get_args (message, &error,
754 DBUS_TYPE_STRING, &goal,
755 DBUS_TYPE_INVALID))
756 {
757 old_goal = instance->properties.goal;
758 instance->properties.goal = strdup (goal);
759 ply_trace ("goal changed from '%s' to '%s'", old_goal, goal);
760 free (old_goal);
761 }
762 dbus_error_free (&error);
763 }
764 return DBUS_HANDLER_RESULT_HANDLED;
765}
766
767static DBusHandlerResult
768state_changed_handler (DBusConnection *connection, DBusMessage *message,
769 ply_upstart_monitor_t *monitor, const char *path)
770{
771 DBusError error;
772 const char *state;
773 ply_upstart_monitor_instance_t *instance;
774 char *old_state;
775
776 ply_trace ("got %s StateChanged", path);
777 instance = ply_hashtable_lookup (monitor->all_instances, (void *) path);
778 if (instance != NULL)
779 {
780 dbus_error_init (&error);
781 if (dbus_message_get_args (message, &error,
782 DBUS_TYPE_STRING, &state,
783 DBUS_TYPE_INVALID))
784 {
785 old_state = instance->properties.state;
786 instance->properties.state = strdup (state);
787 ply_trace ("state changed from '%s' to '%s'", old_state, state);
788 if (strcmp (state, "starting") == 0)
789 {
790 /* Clear any old failed information. */
791 instance->properties.failed = 0;
792 instance->call_failed = false;
793 }
794 if (instance_is_initialized (instance))
795 {
796 if (monitor->state_changed_handler)
797 monitor->state_changed_handler (monitor->state_changed_data,
798 old_state,
799 &instance->job->properties,
800 &instance->properties);
801 }
802 else
803 instance->state_changed = true;
804 free (old_state);
805 }
806 dbus_error_free (&error);
807 }
808 return DBUS_HANDLER_RESULT_HANDLED;
809}
810
811static DBusHandlerResult
812failed_handler (DBusConnection *connection, DBusMessage *message,
813 ply_upstart_monitor_t *monitor, const char *path)
814{
815 DBusError error;
816 ply_upstart_monitor_instance_t *instance;
817 dbus_int32_t failed_status;
818
819 ply_trace ("got %s Failed", path);
820 instance = ply_hashtable_lookup (monitor->all_instances, (void *) path);
821 if (instance != NULL)
822 {
823 dbus_error_init (&error);
824 if (dbus_message_get_args (message, &error,
825 DBUS_TYPE_INT32, &failed_status,
826 DBUS_TYPE_INVALID))
827 {
828 instance->properties.failed = failed_status;
829 if (instance_is_initialized (instance))
830 {
831 if (monitor->failed_handler)
832 monitor->failed_handler (monitor->failed_data,
833 &instance->job->properties,
834 &instance->properties,
835 (int) failed_status);
836 }
837 else
838 instance->call_failed = true;
839 }
840 dbus_error_free (&error);
841 }
842 return DBUS_HANDLER_RESULT_HANDLED;
843}
844
845static DBusHandlerResult
846message_handler (DBusConnection *connection, DBusMessage *message, void *data)
847{
848 ply_upstart_monitor_t *monitor = data;
849 const char *path;
850
851 assert (connection != NULL);
852 assert (message != NULL);
853 assert (monitor != NULL);
854
855 path = dbus_message_get_path (message);
856 if (path == NULL)
857 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
858
859 if (dbus_message_is_signal (message, DBUS_INTERFACE_DBUS,
860 "NameOwnerChanged") &&
861 dbus_message_has_path (message, DBUS_PATH_DBUS) &&
862 dbus_message_has_sender (message, DBUS_SERVICE_DBUS))
863 return name_owner_changed_handler (connection, message, monitor);
864
865 if (dbus_message_is_signal (message, UPSTART_INTERFACE_0_6,
866 "JobAdded"))
867 return job_added_handler (connection, message, monitor);
868
869 if (dbus_message_is_signal (message, UPSTART_INTERFACE_0_6,
870 "JobRemoved"))
871 return job_removed_handler (connection, message, monitor);
872
873 if (dbus_message_is_signal (message, UPSTART_INTERFACE_0_6_JOB,
874 "InstanceAdded"))
875 return instance_added_handler (connection, message, monitor, path);
876
877 if (dbus_message_is_signal (message, UPSTART_INTERFACE_0_6_JOB,
878 "InstanceRemoved"))
879 return instance_removed_handler (connection, message, monitor, path);
880
881 if (dbus_message_is_signal (message, UPSTART_INTERFACE_0_6_INSTANCE,
882 "GoalChanged"))
883 return goal_changed_handler (connection, message, monitor, path);
884
885 if (dbus_message_is_signal (message, UPSTART_INTERFACE_0_6_INSTANCE,
886 "StateChanged"))
887 return state_changed_handler (connection, message, monitor, path);
888
889 if (dbus_message_is_signal (message, UPSTART_INTERFACE_0_6_INSTANCE,
890 "Failed"))
891 return failed_handler (connection, message, monitor, path);
892
893 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
894}
895
896ply_upstart_monitor_t *
897ply_upstart_monitor_new (ply_event_loop_t *loop)
898{
899 DBusError error;
900 DBusConnection *connection;
901 ply_upstart_monitor_t *monitor;
902 char *rule;
903 DBusMessage *message;
904 const char *monitor_service = UPSTART_SERVICE;
905 DBusPendingCall *call;
906
907 dbus_error_init (&error);
908
909 /* Get a connection to the system bus and set it up to listen for messages
910 * from Upstart.
911 */
912 connection = dbus_bus_get (DBUS_BUS_SYSTEM, &error);
913 if (connection == NULL)
914 {
915 ply_error ("unable to connect to system bus: %s", error.message);
916 dbus_error_free (&error);
917 return NULL;
918 }
919 dbus_error_free (&error);
920
921 monitor = calloc (1, sizeof (ply_upstart_monitor_t));
922 monitor->connection = connection;
923 monitor->loop = NULL;
924 monitor->jobs = ply_hashtable_new (ply_hashtable_string_hash,
925 ply_hashtable_string_compare);
926 monitor->all_instances = ply_hashtable_new (ply_hashtable_string_hash,
927 ply_hashtable_string_compare);
928 monitor->state_changed_handler = NULL;
929 monitor->state_changed_data = NULL;
930 monitor->failed_handler = NULL;
931 monitor->failed_data = NULL;
932 monitor->dispatch_fd = -1;
933
934 if (!dbus_connection_add_filter (connection, message_handler, monitor, NULL))
935 {
936 ply_error ("unable to add filter to system bus connection");
937 ply_upstart_monitor_free (monitor);
938 return NULL;
939 }
940
941 asprintf (&rule, "type='%s',sender='%s',path='%s',"
942 "interface='%s',member='%s',arg0='%s'",
943 "signal", DBUS_SERVICE_DBUS, DBUS_PATH_DBUS,
944 DBUS_INTERFACE_DBUS, "NameOwnerChanged", UPSTART_SERVICE);
945 dbus_bus_add_match (connection, rule, &error);
946 free (rule);
947 if (dbus_error_is_set (&error))
948 {
949 ply_error ("unable to add match rule to system bus connection: %s",
950 error.message);
951 ply_upstart_monitor_free (monitor);
952 dbus_error_free (&error);
953 return NULL;
954 }
955
956 asprintf (&rule, "type='%s',sender='%s'", "signal", UPSTART_SERVICE);
957 dbus_bus_add_match (connection, rule, &error);
958 free (rule);
959 if (dbus_error_is_set (&error))
960 {
961 ply_error ("unable to add match rule to system bus connection: %s",
962 error.message);
963 ply_upstart_monitor_free (monitor);
964 dbus_error_free (&error);
965 return NULL;
966 }
967
968 /* Start the state machine going: find out the current owner of the
969 * well-known Upstart name.
970 * Ignore errors: the worst case is that we don't get any messages back
971 * and our state machine does nothing.
972 */
973 ply_trace ("calling GetNameOwner");
974 message = dbus_message_new_method_call (DBUS_SERVICE_DBUS, DBUS_PATH_DBUS,
975 DBUS_INTERFACE_DBUS, "GetNameOwner");
976 dbus_message_append_args (message,
977 DBUS_TYPE_STRING, &monitor_service,
978 DBUS_TYPE_INVALID);
979 dbus_connection_send_with_reply (connection, message, &call, -1);
980 dbus_message_unref (message);
981 if (call != NULL)
982 dbus_pending_call_set_notify (call,
983 (DBusPendingCallNotifyFunction)
984 on_get_name_owner_finished,
985 monitor,
986 NULL);
987
988 if (loop != NULL)
989 ply_upstart_monitor_connect_to_event_loop (monitor, loop);
990
991 return monitor;
992}
993
994void
995ply_upstart_monitor_free (ply_upstart_monitor_t *monitor)
996{
997 if (monitor == NULL)
998 return;
999
1000 ply_hashtable_free (monitor->all_instances);
1001 ply_hashtable_free (monitor->jobs);
1002 dbus_connection_unref (monitor->connection);
1003 if (monitor->dispatch_fd >= 0)
1004 close (monitor->dispatch_fd);
1005 free (monitor);
1006}
1007
1008static void
1009read_watch_handler (void *data, int fd)
1010{
1011 DBusWatch *watch = data;
1012
1013 assert (watch != NULL);
1014
1015 dbus_watch_handle (watch, DBUS_WATCH_READABLE);
1016}
1017
1018static void
1019write_watch_handler (void *data, int fd)
1020{
1021 DBusWatch *watch = data;
1022
1023 assert (watch != NULL);
1024
1025 dbus_watch_handle (watch, DBUS_WATCH_WRITABLE);
1026}
1027
1028static dbus_bool_t
1029add_watch (DBusWatch *watch, void *data)
1030{
1031 ply_upstart_monitor_t *monitor = data;
1032 unsigned int flags;
1033 int fd;
1034 ply_event_loop_fd_status_t status;
1035 ply_fd_watch_t *read_watch_event = NULL, *write_watch_event = NULL;
1036
1037 assert (monitor != NULL);
1038 assert (watch != NULL);
1039
1040 if (!dbus_watch_get_enabled (watch))
1041 return TRUE;
1042
1043 assert (dbus_watch_get_data (watch) == NULL);
1044
1045 flags = dbus_watch_get_flags (watch);
1046 fd = dbus_watch_get_unix_fd (watch);
1047
1048 if (flags & DBUS_WATCH_READABLE)
1049 {
1050 status = PLY_EVENT_LOOP_FD_STATUS_HAS_DATA;
1051 read_watch_event = ply_event_loop_watch_fd (monitor->loop, fd, status,
1052 read_watch_handler, NULL,
1053 watch);
1054 if (read_watch_event == NULL)
1055 return FALSE;
1056 dbus_watch_set_data (watch, read_watch_event, NULL);
1057 }
1058
1059 if (flags & DBUS_WATCH_WRITABLE)
1060 {
1061 status = PLY_EVENT_LOOP_FD_STATUS_CAN_TAKE_DATA;
1062 write_watch_event = ply_event_loop_watch_fd (monitor->loop, fd, status,
1063 write_watch_handler, NULL,
1064 watch);
1065 if (write_watch_event == NULL)
1066 {
1067 if (read_watch_event != NULL)
1068 ply_event_loop_stop_watching_fd (monitor->loop, read_watch_event);
1069 return FALSE;
1070 }
1071 dbus_watch_set_data (watch, write_watch_event, NULL);
1072 }
1073
1074 return TRUE;
1075}
1076
1077static void
1078remove_watch (DBusWatch *watch, void *data)
1079{
1080 ply_upstart_monitor_t *monitor = data;
1081 ply_fd_watch_t *watch_event;
1082
1083 assert (monitor != NULL);
1084 assert (watch != NULL);
1085
1086 watch_event = dbus_watch_get_data (watch);
1087 if (watch_event == NULL)
1088 return;
1089
1090 ply_event_loop_stop_watching_fd (monitor->loop, watch_event);
1091
1092 dbus_watch_set_data (watch, NULL, NULL);
1093}
1094
1095static void
1096toggled_watch (DBusWatch *watch, void *data)
1097{
1098 if (dbus_watch_get_enabled (watch))
1099 add_watch (watch, data);
1100 else
1101 remove_watch (watch, data);
1102}
1103
1104static ply_upstart_monitor_timeout_t *
1105timeout_user_data_new (ply_upstart_monitor_t *monitor, DBusTimeout *timeout)
1106{
1107 ply_upstart_monitor_timeout_t *monitor_timeout;
1108
1109 monitor_timeout = calloc (1, sizeof (ply_upstart_monitor_timeout_t));
1110 monitor_timeout->monitor = monitor;
1111 monitor_timeout->timeout = timeout;
1112
1113 return monitor_timeout;
1114}
1115
1116static void
1117timeout_user_data_free (void *data)
1118{
1119 ply_upstart_monitor_timeout_t *monitor_timeout = data;
1120
1121 free (monitor_timeout);
1122}
1123
1124static void
1125timeout_handler (void *data, ply_event_loop_t *loop)
1126{
1127 ply_upstart_monitor_timeout_t *monitor_timeout = data;
1128
1129 assert (monitor_timeout != NULL);
1130
1131 dbus_timeout_handle (monitor_timeout->timeout);
1132}
1133
1134static dbus_bool_t
1135add_timeout (DBusTimeout *timeout, void *data)
1136{
1137 ply_upstart_monitor_t *monitor = data;
1138 int interval;
1139 ply_upstart_monitor_timeout_t *monitor_timeout;
1140
1141 assert (monitor != NULL);
1142 assert (timeout != NULL);
1143
1144 if (!dbus_timeout_get_enabled (timeout))
1145 return TRUE;
1146
1147 interval = dbus_timeout_get_interval (timeout) * 1000;
1148
1149 monitor_timeout = timeout_user_data_new (monitor, timeout);
1150
1151 ply_event_loop_watch_for_timeout (monitor->loop, (double) interval,
1152 timeout_handler, monitor_timeout);
1153
1154 dbus_timeout_set_data (timeout, monitor_timeout, timeout_user_data_free);
1155
1156 return TRUE;
1157}
1158
1159static void
1160remove_timeout (DBusTimeout *timeout, void *data)
1161{
1162 ply_upstart_monitor_t *monitor = data;
1163 ply_upstart_monitor_timeout_t *monitor_timeout;
1164
1165 assert (monitor != NULL);
1166 assert (timeout != NULL);
1167
1168 monitor_timeout = dbus_timeout_get_data (timeout);
1169 if (monitor_timeout == NULL)
1170 return;
1171
1172 ply_event_loop_stop_watching_for_timeout (monitor->loop,
1173 timeout_handler, monitor_timeout);
1174
1175 dbus_timeout_set_data (timeout, NULL, NULL);
1176}
1177
1178static void
1179toggled_timeout (DBusTimeout *timeout, void *data)
1180{
1181 if (dbus_timeout_get_enabled (timeout))
1182 add_timeout (timeout, data);
1183 else
1184 remove_timeout (timeout, data);
1185}
1186
1187static void
1188dispatch_status (DBusConnection *connection, DBusDispatchStatus new_status,
1189 void *data)
1190{
1191 ply_upstart_monitor_t *monitor = data;
1192 uint64_t event_payload;
1193
1194 assert (monitor != NULL);
1195
1196 if (new_status != DBUS_DISPATCH_DATA_REMAINS)
1197 return;
1198
1199 /* wake up event loop */
1200 event_payload = 1;
1201 ply_write (monitor->dispatch_fd, &event_payload, sizeof (event_payload));
1202}
1203
1204static void
1205dispatch (void *data, int fd)
1206{
1207 ply_upstart_monitor_t *monitor = data;
1208 uint64_t event_payload;
1209
1210 assert (monitor != NULL);
1211
1212 /* reset eventfd to zero */
1213 ply_read (fd, &event_payload, sizeof (event_payload));
1214
1215 while (dbus_connection_dispatch (monitor->connection) ==
1216 DBUS_DISPATCH_DATA_REMAINS)
1217 ;
1218}
1219
1220bool
1221ply_upstart_monitor_connect_to_event_loop (ply_upstart_monitor_t *monitor,
1222 ply_event_loop_t *loop)
1223{
1224 ply_fd_watch_t *dispatch_event = NULL;
1225 uint64_t event_payload;
1226
1227 assert (monitor != NULL);
1228
1229 monitor->loop = loop;
1230 monitor->dispatch_fd = -1;
1231
1232 if (!dbus_connection_set_watch_functions (monitor->connection,
1233 add_watch,
1234 remove_watch,
1235 toggled_watch,
1236 monitor, NULL))
1237 goto err;
1238
1239 if (!dbus_connection_set_timeout_functions (monitor->connection,
1240 add_timeout,
1241 remove_timeout,
1242 toggled_timeout,
1243 monitor, NULL))
1244 goto err;
1245
1246 monitor->dispatch_fd = eventfd (0, EFD_CLOEXEC | EFD_NONBLOCK);
1247 if (monitor->dispatch_fd < 0)
1248 goto err;
1249 /* make sure we wake up to dispatch the first time through */
1250 event_payload = 1;
1251 ply_write (monitor->dispatch_fd, &event_payload, sizeof (event_payload));
1252
1253 dispatch_event = ply_event_loop_watch_fd (monitor->loop,
1254 monitor->dispatch_fd,
1255 PLY_EVENT_LOOP_FD_STATUS_HAS_DATA,
1256 dispatch, NULL, monitor);
1257 if (dispatch_event == NULL)
1258 goto err;
1259
1260 dbus_connection_set_dispatch_status_function (monitor->connection,
1261 dispatch_status,
1262 monitor, NULL);
1263
1264 return true;
1265
1266err:
1267 dbus_connection_set_watch_functions (monitor->connection,
1268 NULL, NULL, NULL, NULL, NULL);
1269 dbus_connection_set_timeout_functions (monitor->connection,
1270 NULL, NULL, NULL, NULL, NULL);
1271 dbus_connection_set_dispatch_status_function (monitor->connection,
1272 NULL, NULL, NULL);
1273 if (dispatch_event != NULL)
1274 ply_event_loop_stop_watching_fd (monitor->loop, dispatch_event);
1275 if (monitor->dispatch_fd >= 0)
1276 {
1277 close (monitor->dispatch_fd);
1278 monitor->dispatch_fd = -1;
1279 }
1280 monitor->loop = NULL;
1281 return false;
1282}
1283
1284void
1285ply_upstart_monitor_add_state_changed_handler (ply_upstart_monitor_t *monitor,
1286 ply_upstart_monitor_state_changed_handler_t handler,
1287 void *user_data)
1288{
1289 monitor->state_changed_handler = handler;
1290 monitor->state_changed_data = user_data;
1291}
1292
1293void
1294ply_upstart_monitor_add_failed_handler (ply_upstart_monitor_t *monitor,
1295 ply_upstart_monitor_failed_handler_t handler,
1296 void *user_data)
1297{
1298 monitor->failed_handler = handler;
1299 monitor->failed_data = user_data;
1300}
1301/* vim: set ts=4 sw=4 expandtab autoindent cindent cino={.5s,(0: */
01302
=== modified file 'debian/changelog'
--- debian/changelog 2014-03-06 17:52:51 +0000
+++ debian/changelog 2014-03-14 10:43:52 +0000
@@ -1,10 +1,32 @@
1plymouth (0.8.8-0ubuntu16) UNRELEASED; urgency=medium1plymouth (0.8.8-0ubuntu16) UNRELEASED; urgency=medium
22
3 [ Steve Langasek ]
3 * Fix debian/patches/tty1-after-boot.patch: when we have multiple4 * Fix debian/patches/tty1-after-boot.patch: when we have multiple
4 non-default console options on the kernel commandline,5 non-default console options on the kernel commandline,
5 local_console_terminal will not be set, so we should avoid the resulting6 local_console_terminal will not be set, so we should avoid the resulting
6 assert. LP: #1160079, LP: #1235231.7 assert. LP: #1160079, LP: #1235231.
78
9 [ Dimitri John Ledkov ] LP: #1292458
10 * debian/patches/use-upstart-private-socket.patch: instead of using
11 system dbus, use private upstart socket in the plymouth-upstart-bridge.
12 * debian/plymouth.plymouth-upstart-bridge.upstart: start
13 plymouth-upstart-bridge on startup, and thus gather a more complete
14 boot.log.
15 * debian/patches/dont-bail-on-dummy-terms.patch: don't bail
16 plymouth-upstart-bridge if TERM is not set and/or running on a dummy
17 terminal, as we can run on those. This makes console-log useful in
18 lxc-containers and actually contain messages from upstart jobs
19 starting and stopping.
20 * debian/patches/no-print-empty-description.patch: do not store
21 description when dbus returns empty string, and thus stop printing
22 empty "Starting... done" messages. LP: #1185560.
23 * debian/plymouth.plymouth-upstart-bridge.upstart: update stop on
24 conditions to stop when plymouth-shutdown finishes.
25 * Make ubuntu-logo theme support scale factor, provide one plymouth
26 theme with scale 1 and another with scale 2, until scale factor can be
27 dynamically detected.
28 * Mark plymouth-upstart-bridge to respawn.
29
8 -- Steve Langasek <steve.langasek@ubuntu.com> Tue, 04 Mar 2014 14:30:16 -080030 -- Steve Langasek <steve.langasek@ubuntu.com> Tue, 04 Mar 2014 14:30:16 -0800
931
10plymouth (0.8.8-0ubuntu15) trusty; urgency=medium32plymouth (0.8.8-0ubuntu15) trusty; urgency=medium
1133
=== modified file 'debian/control'
--- debian/control 2014-02-04 17:07:35 +0000
+++ debian/control 2014-03-14 10:43:52 +0000
@@ -178,7 +178,7 @@
178178
179Package: plymouth-theme-ubuntu-logo179Package: plymouth-theme-ubuntu-logo
180Architecture: any180Architecture: any
181Depends: plymouth, plymouth-label, ${misc:Depends}, ${shlibs:Depends}181Depends: plymouth, plymouth-label, ttf-ubuntu-font-family, ${misc:Depends}, ${shlibs:Depends}
182Provides: plymouth-theme182Provides: plymouth-theme
183Replaces: plymouth (<< 0.8.1-1~)183Replaces: plymouth (<< 0.8.1-1~)
184Description: graphical boot animation and logger - ubuntu-logo theme184Description: graphical boot animation and logger - ubuntu-logo theme
185185
=== added file 'debian/patches/dont-bail-on-dummy-terms.patch'
--- debian/patches/dont-bail-on-dummy-terms.patch 1970-01-01 00:00:00 +0000
+++ debian/patches/dont-bail-on-dummy-terms.patch 2014-03-14 10:43:52 +0000
@@ -0,0 +1,17 @@
1Description: don't bail plymouth-upstart-bridge if TERM is not set
2 and/or running on a dummy terminal, as we can run on those.
3Author: Dimitri John Ledkov <xnox@ubuntu.com>
4
5--- a/src/upstart-bridge/plymouth-upstart-bridge.c
6+++ b/src/upstart-bridge/plymouth-upstart-bridge.c
7@@ -307,7 +307,9 @@
8 if (should_be_verbose && !ply_is_tracing ())
9 ply_toggle_tracing ();
10
11- setupterm (NULL, STDOUT_FILENO, NULL);
12+ /* Don't bail on dummy/hardcopy terminals */
13+ int errret=0;
14+ setupterm (NULL, STDOUT_FILENO, &errret);
15
16 is_connected = ply_boot_client_connect (state.client,
17 (ply_boot_client_disconnect_handler_t)
018
=== added file 'debian/patches/no-print-empty-description.patch'
--- debian/patches/no-print-empty-description.patch 1970-01-01 00:00:00 +0000
+++ debian/patches/no-print-empty-description.patch 2014-03-14 10:43:52 +0000
@@ -0,0 +1,14 @@
1Description: do not store empty descriptions
2Author: Dimitri John Ledkov <xnox@ubuntu.com>
3
4--- plymouth-0.8.8.orig/src/upstart-bridge/ply-upstart-monitor.c
5+++ plymouth-0.8.8/src/upstart-bridge/ply-upstart-monitor.c
6@@ -273,7 +273,7 @@ on_get_all_job_properties_finished (DBus
7 DBUS_TYPE_STRING)
8 goto next_item;
9 dbus_message_iter_get_basic (&variant_iter, &description);
10- if (description != NULL)
11+ if (description != NULL && description[0])
12 {
13 ply_trace ("description = '%s'", description);
14 job->properties.description = strdup (description);
015
=== modified file 'debian/patches/series'
--- debian/patches/series 2013-12-02 04:53:37 +0000
+++ debian/patches/series 2014-03-14 10:43:52 +0000
@@ -13,3 +13,7 @@
13Miscellaneous-fixes-for-compiler-warnings.patch13Miscellaneous-fixes-for-compiler-warnings.patch
14autoreconf.patch14autoreconf.patch
15details-update-status.patch15details-update-status.patch
16use-upstart-private-socket.patch
17dont-bail-on-dummy-terms.patch
18no-print-empty-description.patch
19ubuntu-logo-scale-factor-2.patch
1620
=== added file 'debian/patches/ubuntu-logo-scale-factor-2.patch'
--- debian/patches/ubuntu-logo-scale-factor-2.patch 1970-01-01 00:00:00 +0000
+++ debian/patches/ubuntu-logo-scale-factor-2.patch 2014-03-14 10:43:52 +0000
@@ -0,0 +1,1202 @@
1Description: Make ubuntu-logo theme support scale factor, provide one plymouth
2 theme with scale 1 and another with scale 2, until scale factor can be
3 dynamically detected.
4Author: Dimitri John Ledkov <xnox@ubuntu.com>
5
6--- a/themes/ubuntu-logo/Makefile.am
7+++ b/themes/ubuntu-logo/Makefile.am
8@@ -1,6 +1,7 @@
9 themedir = $(datadir)/plymouth/themes/ubuntu-logo
10-nodist_theme_DATA = ubuntu-logo.plymouth
11+nodist_theme_DATA = ubuntu-logo.plymouth ubuntu-logo-scale-2.plymouth
12 dist_theme_DATA = ubuntu-logo.script \
13+ ubuntu-logo-scale-2.script \
14 ubuntu-logo.grub \
15 ubuntu_logo.png \
16 ubuntu_logo16.png \
17@@ -13,11 +14,23 @@
18
19
20
21-MAINTAINERCLEANFILES = Makefile.in ubuntu-logo.plymouth
22-CLEANFILES = ubuntu-logo.plymouth
23+MAINTAINERCLEANFILES = Makefile.in ubuntu-logo.plymouth ubuntu-logo-scale-2.plymouth ubuntu-logo.script ubuntu-logo-scale-2.script
24+CLEANFILES = ubuntu-logo.plymouth ubuntu-logo-scale-2.plymouth ubuntu-logo.script ubuntu-logo-scale-2.script
25
26 ubuntu-logo.plymouth: $(srcdir)/ubuntu-logo.plymouth.in
27- sed -e 's,[@]PLYMOUTH_THEME_PATH[@],$(PLYMOUTH_THEME_PATH),g' \
28+ sed -e 's,[@]PLYMOUTH_THEME_PATH[@],$(PLYMOUTH_THEME_PATH),g;s,[@]EXTRA_NAME[@],,g;s,[@]SCRIPT_NAME[@],ubuntu-logo,g' \
29 $(srcdir)/ubuntu-logo.plymouth.in > ubuntu-logo.plymouth
30
31-EXTRA_DIST = ubuntu-logo.plymouth.in
32+ubuntu-logo-scale-2.plymouth: $(srcdir)/ubuntu-logo.plymouth.in
33+ sed -e 's,[@]PLYMOUTH_THEME_PATH[@],$(PLYMOUTH_THEME_PATH),g;s,[@]EXTRA_NAME[@],(Scale x2),g;s,[@]SCRIPT_NAME[@],ubuntu-logo-scale-2,g' \
34+ $(srcdir)/ubuntu-logo.plymouth.in > ubuntu-logo-scale-2.plymouth
35+
36+ubuntu-logo.script: $(srcdir)/ubuntu-logo.script.in
37+ sed -e 's,[@]SCALEFACTOR[@],1,g' \
38+ $(srcdir)/ubuntu-logo.script.in > ubuntu-logo.script
39+
40+ubuntu-logo-scale-2.script: $(srcdir)/ubuntu-logo.script.in
41+ sed -e 's,[@]SCALEFACTOR[@],2,g' \
42+ $(srcdir)/ubuntu-logo.script.in > ubuntu-logo-scale-2.script
43+
44+EXTRA_DIST = ubuntu-logo.plymouth.in ubuntu-logo.script.in
45--- a/themes/ubuntu-logo/ubuntu-logo.plymouth.in
46+++ b/themes/ubuntu-logo/ubuntu-logo.plymouth.in
47@@ -1,8 +1,8 @@
48 [Plymouth Theme]
49-Name=Ubuntu Logo
50+Name=Ubuntu Logo @EXTRA_NAME@
51 Description=A theme that features a blank background with a logo.
52 ModuleName=script
53
54 [script]
55 ImageDir=@PLYMOUTH_THEME_PATH@/ubuntu-logo
56-ScriptFile=@PLYMOUTH_THEME_PATH@/ubuntu-logo/ubuntu-logo.script
57+ScriptFile=@PLYMOUTH_THEME_PATH@/ubuntu-logo/@SCRIPT_NAME@.script
58--- /dev/null
59+++ b/themes/ubuntu-logo/ubuntu-logo.script.in
60@@ -0,0 +1,1142 @@
61+# ubuntu-logo.script - boot splash plugin
62+#
63+# Copyright (C) 2009 Canonical Ltd.
64+#
65+# This program is free software; you can redistribute it and/or modify
66+# it under the terms of the GNU General Public License as published by
67+# the Free Software Foundation; either version 2, or (at your option)
68+# any later version.
69+#
70+# This program is distributed in the hope that it will be useful,
71+# but WITHOUT ANY WARRANTY; without even the implied warranty of
72+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
73+# GNU General Public License for more details.
74+#
75+# You should have received a copy of the GNU General Public License
76+# along with this program; if not, write to the Free Software
77+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
78+# 02111-1307, USA.
79+#
80+# Written by: Alberto Milone <alberto.milone@canonical.com>
81+#
82+# Based on the example provided with the "script plugin" written by:
83+# Charlie Brej <cbrej@cs.man.ac.uk>
84+#
85+# Question stuff written by: Markus Waas <mail@markuswaas.de>
86+#
87+#
88+
89+# Set the text colour in (rgb / 256)
90+text_colour.red = 1.0;
91+text_colour.green = 1.0;
92+text_colour.blue = 1.0;
93+
94+# Tinted text #988592
95+tinted_text_colour.red = 0.59;
96+tinted_text_colour.green = 0.52;
97+tinted_text_colour.blue = 0.57;
98+
99+# Action Text - #ffffff - RGB 255 255 255
100+action_text_colour.red = 1.0;
101+action_text_colour.green = 1.0;
102+action_text_colour.blue = 1.0;
103+
104+# Orange - #ff4012 - RGB 255 64 18
105+debugsprite = Sprite();
106+debugsprite_bottom = Sprite();
107+debugsprite_medium = Sprite();
108+
109+# Ubuntu Font
110+ubuntufont = "Ubuntu 11";
111+ubuntualignment = "center";
112+
113+# Scale factor
114+scalefactor = @SCALEFACTOR@;
115+
116+# are we currently prompting for a password?
117+prompt_active = 0;
118+
119+# Generic scalable image loader
120+fun LoadScaleImage (imagepath) {
121+ image = Image (imagepath);
122+ image = image.Scale (image.GetWidth() * scalefactor, image.GetHeight() * scalefactor);
123+ return image;
124+}
125+
126+# General purpose function to create text
127+fun WriteText (text, colour) {
128+ image = Image.Text (text, colour.red, colour.green, colour.blue, color.alpha, ubuntufont, ubuntualignment);
129+ image = image.Scale (image.GetWidth() * scalefactor, image.GetHeight() * scalefactor);
130+ return image;
131+}
132+
133+fun ImageToText (text) {
134+ image = WriteText (text, text_colour);
135+ return image;
136+}
137+
138+fun ImageToTintedText (text) {
139+ image = WriteText (text, tinted_text_colour);
140+ return image;
141+}
142+
143+fun ImageToActionText (text) {
144+ image = WriteText (text, action_text_colour);
145+ return image;
146+}
147+
148+fun Debug(text) {
149+ debugsprite.SetImage(ImageToText (text));
150+}
151+
152+fun DebugBottom(text) {
153+ debugsprite_bottom.SetImage(ImageToText (text));
154+ debugsprite_bottom.SetPosition(0, (Window.GetHeight (0) - 20), 1);
155+}
156+
157+fun DebugMedium(text) {
158+ debugsprite_medium.SetImage(ImageToText (text));
159+ debugsprite_medium.SetPosition(0, (Window.GetHeight (0) - 60), 1);
160+}
161+
162+fun TextYOffset() {
163+ local.y;
164+ local.text_height;
165+ local.min_height;
166+
167+ # Put the 1st line below the logo + some spacing
168+ y = logo.y + logo.height + (progress_indicator.bullet_height * 7 ); # + logo_spacing;
169+
170+ text_height = first_line_height * 7.5;
171+
172+ min_height = Window.GetHeight();
173+ if (y + text_height > min_height)
174+ y = min_height - text_height;
175+
176+ if (y < progress_indicator.y + progress_indicator.height)
177+ return progress_indicator.y + progress_indicator.height;
178+ return y;
179+}
180+
181+#------------------------------String functions-------------------------------
182+
183+# This is the equivalent for strstr()
184+fun StringString(string, substring) {
185+ start = 0;
186+ while (String(string).CharAt (start)) {
187+ walk = 0;
188+ while (String(substring).CharAt (walk) == String(string).CharAt (start + walk) ) {
189+ walk++;
190+ if (!String(substring).CharAt (walk)) return start;
191+ }
192+ start++;
193+ }
194+
195+ return NULL;
196+}
197+
198+fun StringLength (string) {
199+ index = 0;
200+ while (String(string).CharAt(index)) index++;
201+ return index;
202+}
203+
204+fun StringCopy (source, beginning, end) {
205+ local.destination = "";
206+ for (index = beginning; ( ( (end == NULL) || (index <= end) ) && (String(source).CharAt(index)) ); index++) {
207+ local.destination += String(source).CharAt(index);
208+ }
209+
210+ return local.destination;
211+}
212+
213+fun StringReplace (source, pattern, replacement) {
214+ local.found = StringString(source, pattern);
215+ if (local.found == NULL)
216+ return source;
217+
218+ local.new_string = StringCopy (source, 0, local.found - 1) +
219+ replacement +
220+ StringCopy (source, local.found + StringLength(pattern), NULL);
221+
222+ return local.new_string;
223+}
224+
225+# it makes sense to use it only for
226+# numbers up to 100
227+fun StringToInteger (str) {
228+ int = -1;
229+ for (i=0; i<=100; i++) {
230+ if (i+"" == str) {
231+ int = i;
232+ break;
233+ }
234+ }
235+ return int;
236+}
237+
238+#-----------------------------------------------------------------------------
239+# Previous background colour
240+# #300a24 --> 0.19, 0.04, 0.14
241+# New background colour
242+# #2c001e --> 0.16, 0.00, 0.12
243+#
244+Window.SetBackgroundTopColor (0.16, 0.00, 0.12); # Nice colour on top of the screen fading to
245+Window.SetBackgroundBottomColor (0.16, 0.00, 0.12); # an equally nice colour on the bottom
246+
247+bits_per_pixel = Window.GetBitsPerPixel ();
248+if (bits_per_pixel == 4) {
249+ logo_filename = "ubuntu_logo16.png";
250+ progress_dot_off_filename = "progress_dot_off16.png";
251+ progress_dot_on_filename = "progress_dot_on16.png";
252+ password_field_filename = "password_field16.png";
253+ question_field_filename = "password_field16.png";
254+} else {
255+ logo_filename = "ubuntu_logo.png";
256+ progress_dot_off_filename = "progress_dot_off.png";
257+ progress_dot_on_filename = "progress_dot_on.png";
258+ password_field_filename = "password_field.png";
259+ question_field_filename = "password_field.png";
260+}
261+
262+logo.image = LoadScaleImage (logo_filename);
263+logo.sprite = Sprite ();
264+logo.sprite.SetImage (logo.image);
265+logo.width = logo.image.GetWidth ();
266+logo.height = logo.image.GetHeight ();
267+logo.x = Window.GetX () + Window.GetWidth () / 2 - logo.width / 2;
268+logo.y = Window.GetY () + Window.GetHeight () / 2 - logo.height;
269+logo.z = 1000;
270+logo.sprite.SetX (logo.x);
271+logo.sprite.SetY (logo.y);
272+logo.sprite.SetZ (logo.z);
273+logo.sprite.SetOpacity (1);
274+
275+# Spacing below the logo - in pixels
276+logo_spacing = logo.height * 4;
277+
278+message_notification[0].image = ImageToTintedText ("");
279+message_notification[1].image = ImageToTintedText ("");
280+fsck_notification.image = ImageToActionText ("");
281+
282+status = "normal";
283+
284+progress_indicator.bullet_off = LoadScaleImage (progress_dot_off_filename);
285+progress_indicator.bullet_on = LoadScaleImage (progress_dot_on_filename);
286+progress_indicator.bullet_width = progress_indicator.bullet_off.GetWidth ();
287+progress_indicator.bullet_height = progress_indicator.bullet_off.GetHeight ();
288+progress_indicator.bullet_hspacing = progress_indicator.bullet_width * 1.1;
289+progress_indicator.width = progress_indicator.bullet_width * 5;
290+progress_indicator.height = progress_indicator.bullet_height;
291+progress_indicator.y = logo.y + logo.height + (logo.height / 4);
292+progress_indicator.x = Window.GetX () + Window.GetWidth () / 2 - progress_indicator.width / 2; # logo.x + 26;
293+
294+# use a fixed string with ascending and descending stems to calibrate the
295+# bounding box for the first message, so the messages below don't move up
296+# and down according to *their* height.
297+first_line_height = ImageToTintedText ("AfpqtM").GetHeight();
298+
299+# if the user has a 640x480 or 800x600 display, we can't quite fit everything
300+# (including passphrase prompts) with the target spacing, so scoot the text up
301+# a bit if needed.
302+top_of_the_text = TextYOffset();
303+
304+#-----------------------------------------Logo functions------------------------------
305+
306+# Call this when updating the screen
307+fun draw_logo () {
308+ logo.sprite.SetX (logo.x);
309+ logo.sprite.SetY (logo.y);
310+ logo.sprite.SetZ (logo.z);
311+ logo.sprite.SetOpacity (1);
312+}
313+
314+
315+#-----------------------------------------Progress Indicator--------------------------
316+fun set_progress_indicator () {
317+
318+
319+ # Here we assume that we can store half bullets on each half of the screen
320+ # together with some spacing
321+ local.x = progress_indicator.x;
322+
323+ for (index = 0; index <= 4; index++) {
324+ # Set the "off" bullets
325+ progress_indicator.bullets_off[index].sprite = Sprite (progress_indicator.bullet_off);
326+ progress_indicator.bullets_off[index].sprite.SetPosition (local.x, progress_indicator.y, 1000);
327+ progress_indicator.bullets_off[index].x = local.x;
328+ progress_indicator.bullets_off[index].y = progress_indicator.y;
329+ progress_indicator.bullets_off[index].sprite.SetOpacity (1);
330+
331+ #local.debug_medium_string = "Progress indicator " + index + ": x = " + progress_indicator.bullets_off[index].x +
332+ # ", y = " + progress_indicator.bullets_off[index].y + ", logo width = " + logo.width +
333+ # ", logo height = " + logo.height + " " + screen_width + " " + screen_height;
334+ #
335+ #(index % 2) && DebugMedium (local.debug_medium_string) || DebugBottom (local.debug_medium_string);
336+
337+ # Set the "on" bullets on top of the "off" bullets and make them transparent
338+ progress_indicator.bullets_on[index].sprite = Sprite (progress_indicator.bullet_on);
339+ progress_indicator.bullets_on[index].x = progress_indicator.bullets_off[index].x;
340+ progress_indicator.bullets_on[index].y = progress_indicator.bullets_off[index].y;
341+ progress_indicator.bullets_on[index].sprite.SetPosition (progress_indicator.bullets_on[index].x, progress_indicator.bullets_on[index].y, 10000);
342+
343+ progress_indicator.bullets_on[index].sprite.SetOpacity (0);
344+
345+ local.x += progress_indicator.bullet_hspacing;
346+ }
347+ #local.debug_string = "Progress indicator: x1 = " + progress_indicator.x + ", x2 = " + local.x + ", y = " + progress_indicator.y +
348+ # ", x logo = " + logo.x + ", y logo = " + logo.y + ", indicator width = " + progress_indicator.width;
349+ #Debug(progress_indicator.bullets_off[0].x);
350+}
351+
352+
353+# We have 2 bullets, one on top of the other:
354+# The white one is on top of the red one and the former should
355+# slowly fade so as to get a nice transition effect.
356+fun switch_on_bullet (bullets_off, bullets_on, bullet_number, opacity) {
357+ local.x = bullets_on[bullet_number].x;
358+ local.y = bullets_on[bullet_number].y;
359+ local.z = bullets_on[bullet_number].z;
360+
361+ # Hide the bullets which are off
362+ bullets_off[bullet_number].sprite.SetOpacity (0);
363+
364+ # Show the bullets which are on
365+ bullets_on[bullet_number].sprite.SetPosition (local.x, local.y, local.z);
366+ bullets_on[bullet_number].sprite.SetOpacity (opacity);
367+
368+ # Bump the number of times we have switched on bullets
369+ global.times_bullets_switched++;
370+}
371+
372+fun switch_off_bullets () {
373+ # Debug("Switching off progress indicator");
374+
375+ set_progress_indicator ();
376+ global.times_bullets_switched = 0;
377+ global.on_off = 1;
378+}
379+
380+# This is something that we can call when we exit
381+fun switch_on_bullets () {
382+ # Debug("Switching off progress indicator");
383+ if (!global.progress_indicator.bullets_on) set_progress_indicator ();
384+ local = global.progress_indicator;
385+
386+ for (index = 0; bullets_on[index]; index++) {
387+ switch_on_bullet (bullets_off, bullets_on, index, 1.0);
388+ }
389+}
390+
391+
392+# Implement in boot progress callback
393+fun animate_progress_indicator (progress, time) {
394+ if (global.progress_time == NULL) {
395+ global.progress_time = progress; #time;
396+ switch_off_bullets ();
397+ }
398+
399+# Debug ("progress = " + progress + ", time = " + time + " times switched = " + global.times_bullets_switched + " on_off " + global.on_off);
400+
401+# if (global.times_bullets_switched == NULL)
402+# global.times_bullets_switched = 5;
403+
404+# if (global.on_off == NULL)
405+# global.on_off = 0;
406+
407+ if ((progress - global.progress_time) >= 1.0) {
408+ global.progress_time = progress;
409+
410+ if (global.times_bullets_switched == 5) {
411+ # Change which bullets are switched on
412+ # and which ones are switched off
413+ global.on_off = !global.on_off;
414+ global.times_bullets_switched = 0;
415+ }
416+
417+ if (global.on_off) {
418+ switch_on_bullet (progress_indicator.bullets_off, progress_indicator.bullets_on,
419+ global.times_bullets_switched, 1.0);
420+ }
421+ else {
422+ switch_on_bullet (progress_indicator.bullets_on, progress_indicator.bullets_off,
423+ global.times_bullets_switched, 1.0);
424+ }
425+ }
426+
427+
428+ # Start setting bullets to "on" with translucency
429+# for (index = 0; index <= 5; index++) {
430+# opacity = 0.0;
431+# while (opacity <= 1.0) {
432+# switch_on_bullet (progress_indicator.bullets_off, progress_indicator.bullets_on,
433+# index, opacity);
434+# opacity += 0.1;
435+# }
436+# }
437+}
438+
439+
440+#-----------------------------------------Label utility functions---------------------
441+
442+# label should be either a string or NULL
443+# Images for n lines will be created and returned as items of the
444+# message_label array
445+#
446+fun get_message_label (label, is_fake, is_action_line) {
447+ # Debug("Get Label position");
448+ local.message_label;
449+
450+ if (is_fake)
451+ # Create a fake label so as to get the y coordinate of
452+ # a standard-length label.
453+ local.message_image = ImageToTintedText ("This is a fake message");
454+ else
455+ local.message_image = (is_action_line) && ImageToActionText (label) || ImageToTintedText (label);
456+
457+ message_label.width = message_image.GetWidth ();
458+ message_label.height = message_image.GetHeight ();
459+
460+ # Center the line horizontally
461+ message_label.x = Window.GetX () + Window.GetWidth () / 2 - message_label.width / 2;
462+
463+ message_label.y = top_of_the_text;
464+
465+ # Put the 2nd line below the fsck line
466+ if (is_action_line) {
467+ local.fsck_label.y = message_label.y + (first_line_height + first_line_height / 2);
468+ message_label.y = local.fsck_label.y + (first_line_height * 2);
469+ }
470+
471+ # Debug("action label x = " + message_label.x + " y = " + message_label.y );
472+
473+# message_debug = "msg_x = " + message_label.x + " msg_y = " + message_label.y +
474+# "msg_width = " + message_label.width + " msg_height = " +
475+# message_label.height + " message = " + label;
476+# Debug(message_debug);
477+
478+ return message_label;
479+
480+}
481+
482+# Create an fsck label and/or get its position
483+fun get_fsck_label (label, is_fake) {
484+ # Debug("Get Label position");
485+ local.fsck_label = global.progress_label;
486+
487+ if (is_fake)
488+ fsck_label.image = ImageToTintedText ("This is a fake message");
489+ else
490+ fsck_label.image = ImageToTintedText (label);
491+
492+ fsck_label.width = fsck_label.image.GetWidth ();
493+ fsck_label.height = fsck_label.image.GetHeight ();
494+
495+ # Centre the label horizontally
496+ fsck_label.x = Window.GetX () + Window.GetWidth () / 2 - fsck_label.width / 2;
497+
498+ local.first_label = get_message_label (label, 1, 0);
499+
500+ # Place the label below the 1st message line
501+ fsck_label.y = local.first_label.y + local.first_label.height + (local.first_label.height / 2);
502+
503+# message_debug = "msg_x = " + fsck_label.x + " msg_y = " + fsck_label.y +
504+# "msg_width = " + fsck_label.width + " msg_height = " +
505+# fsck_label.height + " message = " + label;
506+# Debug(message_debug);
507+
508+ return fsck_label;
509+}
510+
511+#-----------------------------------------Message stuff --------------------------------
512+#
513+
514+# Set up a message label
515+#
516+# NOTE: this is called when doing something like 'plymouth message "hello world"'
517+#
518+fun setup_message (message_text, x, y, z, index) {
519+ # Debug("Message setup");
520+ global.message_notification[index].image = (index) && ImageToActionText (message_text) || ImageToTintedText (message_text);
521+
522+ # Set up the text message, if any
523+ message_notification[index].x = x;
524+ message_notification[index].y = y;
525+ message_notification[index].z = z;
526+
527+ message_notification[index].sprite = Sprite ();
528+ message_notification[index].sprite.SetImage (message_notification[index].image);
529+ message_notification[index].sprite.SetX (message_notification[index].x);
530+ message_notification[index].sprite.SetY (message_notification[index].y);
531+ message_notification[index].sprite.SetZ (message_notification[index].z);
532+
533+}
534+
535+fun show_message (index) {
536+ if (global.message_notification[index].sprite) global.message_notification[index].sprite.SetOpacity(1);
537+}
538+
539+fun hide_message (index) {
540+ if (global.message_notification[index].sprite) global.message_notification[index].sprite.SetOpacity(0);
541+}
542+
543+
544+
545+
546+# the callback function is called when new message should be displayed.
547+# First arg is message to display.
548+fun message_callback (message)
549+{
550+ # Debug("Message callback");
551+ is_fake = 0;
552+ if (!message || (message == "")) is_fake = 1;
553+
554+ local.substring = "keys:";
555+
556+ # Look for the "keys:" prefix
557+ local.keys = StringString(message, local.substring);
558+
559+ local.is_action_line = (keys != NULL);
560+ #Debug("keys " + local.keys + " substring length = " + StringLength(local.substring));
561+
562+ # Get the message without the "keys:" prefix
563+ if (keys != NULL)
564+ message = StringCopy (message, keys + StringLength(local.substring), NULL);
565+
566+ local.label.is_fake = is_fake;
567+ label = get_message_label(message, is_fake, is_action_line);
568+ label.z = 10000;
569+
570+ setup_message (message, label.x, label.y, label.z, is_action_line);
571+ if (prompt_active && local.is_action_line)
572+ hide_message (is_action_line);
573+ else
574+ show_message (is_action_line);
575+
576+}
577+
578+
579+#-----------------------------------------Display Password stuff -----------------------
580+#
581+
582+fun password_dialogue_setup (message_label) {
583+ # Debug("Password dialog setup");
584+
585+ local.entry;
586+ local.bullet_image;
587+ bullet_image = LoadScaleImage (progress_dot_off_filename);
588+ entry.image = LoadScaleImage (password_field_filename);
589+
590+ # Hide the normal labels
591+ prompt_active = 1;
592+ if (message_notification[1].sprite) hide_message (1);
593+
594+ # Set the prompt label
595+ label = get_message_label(message_label, 0, 1);
596+ label.z = 10000;
597+
598+ setup_message (message_label, label.x, label.y, label.z, 2);
599+ show_message (2);
600+
601+ # Set up the text entry which contains the bullets
602+ entry.sprite = Sprite ();
603+ entry.sprite.SetImage (entry.image);
604+
605+ # Centre the box horizontally
606+ entry.x = Window.GetX () + Window.GetWidth () / 2 - entry.image.GetWidth () / 2;
607+
608+ # Put the entry below the second label.
609+ entry.y = message_notification[2].y + label.height;
610+
611+ #Debug ("entry x = " + entry.x + ", y = " + entry.y);
612+ entry.z = 10000;
613+ entry.sprite.SetX (entry.x);
614+ entry.sprite.SetY (entry.y);
615+ entry.sprite.SetZ (entry.z);
616+
617+ global.password_dialogue = local;
618+}
619+
620+fun password_dialogue_opacity (opacity) {
621+ # Debug("Password dialog opacity");
622+ global.password_dialogue.opacity = opacity;
623+ local = global.password_dialogue;
624+
625+ # You can make the box translucent with a float
626+ # entry.sprite.SetOpacity (0.3);
627+ entry.sprite.SetOpacity (opacity);
628+ label.sprite.SetOpacity (opacity);
629+
630+ if (bullets) {
631+ for (index = 0; bullets[index]; index++) {
632+ bullets[index].sprite.SetOpacity (opacity);
633+ }
634+ }
635+}
636+
637+
638+# The callback function is called when the display should display a password dialogue.
639+# First arg is prompt string, the second is the number of bullets.
640+fun display_password_callback (prompt, bullets) {
641+ # Debug("Password dialog setup");
642+
643+ global.status = "password";
644+ if (!global.password_dialogue) password_dialogue_setup(prompt);
645+ password_dialogue_opacity (1);
646+ bullet_width = password_dialogue.bullet_image.GetWidth();
647+ bullet_y = password_dialogue.entry.y +
648+ password_dialogue.entry.image.GetHeight () / 2 -
649+ password_dialogue.bullet_image.GetHeight () / 2;
650+ margin = bullet_width;
651+ spaces = Math.Int( (password_dialogue.entry.image.GetWidth () - (margin * 2) ) / ( 2 * bullet_width / 3 ) );
652+ #Debug ("spaces = " + spaces + ", bullets = " + bullets);
653+ bullets_area.width = margin + spaces * ( 2 * bullet_width / 3);
654+ bullets_area.x = Window.GetX () + Window.GetWidth () / 2 - bullets_area.width / 2;
655+ #DebugBottom ("pwd_entry x = " + password_dialogue.entry.x + ", bullets_area.x = " + bullets_area.x + ", bullets_area.width = " + bullets_area.width);
656+ if (bullets > spaces)
657+ bullets = spaces;
658+ for (index = 0; password_dialogue.bullets[index] || index < spaces ; index++){
659+ if (!password_dialogue.bullets[index]) {
660+ password_dialogue.bullets[index].sprite = Sprite ();
661+ password_dialogue.bullets[index].sprite.SetImage (password_dialogue.bullet_image);
662+ password_dialogue.bullets[index].x = bullets_area.x + # password_dialogue.entry.x + margin +
663+ index * ( 2 * bullet_width / 3 ) ;
664+ password_dialogue.bullets[index].sprite.SetX (password_dialogue.bullets[index].x);
665+ password_dialogue.bullets[index].y = bullet_y;
666+ password_dialogue.bullets[index].sprite.SetY (password_dialogue.bullets[index].y);
667+ password_dialogue.bullets[index].z = password_dialogue.entry.z + 100 - index;
668+ password_dialogue.bullets[index].sprite.SetZ (password_dialogue.bullets[index].z);
669+ }
670+
671+ password_dialogue.bullets[index].sprite.SetOpacity (0);
672+
673+ if (index < bullets ) {
674+ password_dialogue.bullets[index].sprite.SetOpacity (1);
675+ }
676+ }
677+}
678+
679+Plymouth.SetDisplayPasswordFunction (display_password_callback);
680+
681+Plymouth.SetMessageFunction (message_callback);
682+
683+Plymouth.SetBootProgressFunction (animate_progress_indicator);
684+
685+# Plymouth.SetBootProgressFunction: the callback function is called with two numbers, the progress (between 0 and 1) and the time spent booting so far
686+# Plymouth.SetRootMountedFunction: the callback function is called when a new root is mounted
687+# Plymouth.SetKeyboardInputFunction: the callback function is called with a string containing a new character entered on the keyboard
688+
689+#----------------------------------------- FSCK Counter --------------------------------
690+
691+# Initialise the counter
692+fun init_fsck_count () {
693+ # The number of fsck checks in this cycle
694+ global.counter.total = 0;
695+ # The number of fsck checks already performed + the current one
696+ global.counter.current = 1;
697+ # The previous fsck
698+ global.counter.last = 0;
699+}
700+
701+# Increase the total counter
702+fun increase_fsck_count () {
703+ global.counter.total++;
704+}
705+
706+fun increase_current_fsck_count () {
707+ global.counter.last = global.counter.current++;
708+}
709+
710+# Clear the counter
711+fun clear_fsck_count () {
712+ global.counter = NULL;
713+ init_fsck_count ();
714+}
715+
716+#----------------------------------------- Progress Label ------------------------------
717+
718+
719+# Change the opacity level of a progress label
720+#
721+# opacity = 1 -> show
722+# opacity = 0 -> hide
723+# opacity = 0.3 (or any other float) -> translucent
724+#
725+fun set_progress_label_opacity (opacity) {
726+ # the label
727+ progress_label.sprite.SetOpacity (opacity);
728+
729+ # Make the slot available again when hiding the bar
730+ # So that another bar can take its place
731+ if (opacity == 0) {
732+ progress_label.is_available = 1;
733+ progress_label.device = "";
734+ }
735+}
736+
737+# Set up a new Progress Bar
738+#
739+# TODO: Make it possible to reuse (rather than recreate) a bar
740+# if .is_available = 1. Ideally this would just reset the
741+# label, the associated
742+# device and the image size of the sprite.
743+
744+fun init_progress_label (device, status_string) {
745+ # Make the slot unavailable
746+ global.progress_label.is_available = 0;
747+ progress_label.progress = 0;
748+ progress_label.device = device;
749+ progress_label.status_string = status_string;
750+}
751+
752+# See if the progress label is keeping track of the fsck
753+# of "device"
754+#
755+fun device_has_progress_label (device) {
756+ #DebugBottom ("label device = " + progress_label.device + " checking device " + device);
757+ return (progress_label.device == device);
758+}
759+
760+# Update the Progress bar which corresponds to index
761+#
762+fun update_progress_label (progress) {
763+ # If progress is NULL then we just refresh the label.
764+ # This happens when only counter.total has changed.
765+ if (progress != NULL) {
766+ progress_label.progress = progress;
767+
768+ #Debug("device " + progress_label.device + " progress " + progress);
769+
770+ # If progress >= 100% hide the label and make it available again
771+ if (progress >= 100) {
772+ set_progress_label_opacity (0);
773+
774+ # See if we any other fsck check is complete
775+ # and, if so, hide the progress bars and the labels
776+ on_fsck_completed ();
777+
778+ return 0;
779+ }
780+ }
781+ # Update progress label here
782+ #
783+ # FIXME: the queue logic from this theme should really be moved into mountall
784+ # instead of using string replacement to deal with localised strings.
785+ label = StringReplace (progress_label.status_string[0], "%1$d", global.counter.current);
786+ label = StringReplace (label, "%2$d", global.counter.total);
787+ label = StringReplace (label, "%3$d", progress_label.progress);
788+ label = StringReplace (label, "%%", "%");
789+
790+ progress_label = get_fsck_label (label, 0);
791+ #progress_label.progress = progress;
792+
793+ progress_label.sprite = Sprite (progress_label.image);
794+
795+ # Set up the bar
796+ progress_label.sprite.SetPosition(progress_label.x, progress_label.y, 1);
797+
798+ set_progress_label_opacity (1);
799+
800+}
801+
802+# Refresh the label so as to update counters
803+fun refresh_progress_label () {
804+ update_progress_label (NULL);
805+}
806+
807+#----------------------------------------- FSCK Queue ----------------------------------
808+
809+# Initialise the fsck queue
810+fun init_queue () {
811+ global.fsck_queue[0].device;
812+ global.fsck_queue[0].progress;
813+ global.fsck_queue.counter = 0;
814+ global.fsck_queue.biggest_item = 0;
815+}
816+
817+fun clear_queue () {
818+ global.fsck_queue = NULL;
819+ init_queue ();
820+}
821+
822+# Return either the device index in the queue or -1
823+fun queue_look_up_by_device (device) {
824+ for (i=0; i <= fsck_queue.biggest_item; i++) {
825+ if ((fsck_queue[i]) && (fsck_queue[i].device == device))
826+ return i;
827+ }
828+ return -1;
829+}
830+
831+# Keep track of an fsck process in the queue
832+fun add_fsck_to_queue (device, progress) {
833+ # Look for an empty slot in the queue
834+ for (i=0; global.fsck_queue[i].device; i++) {
835+ continue;
836+ }
837+ local.index = i;
838+
839+ # Set device and progress
840+ global.fsck_queue[local.index].device = device;
841+ global.fsck_queue[local.index].progress = progress;
842+
843+ # Increase the queue counter
844+ global.fsck_queue.counter++;
845+
846+ # Update the max index of the array for iterations
847+ if (local.index > global.fsck_queue.biggest_item)
848+ global.fsck_queue.biggest_item = local.index;
849+
850+ #DebugMedium ("Adding " + device + " at " + local.index);
851+}
852+
853+fun is_queue_empty () {
854+ return (fsck_queue.counter == 0);
855+}
856+
857+fun is_progress_label_available () {
858+ return (progress_label.is_available == 1);
859+}
860+
861+
862+# This should cover the case in which the fsck checks in
863+# the queue are completed before the ones showed in the
864+# progress label
865+fun on_queued_fsck_completed () {
866+ if (!is_queue_empty ())
867+ return;
868+
869+ # Hide the extra label, if any
870+ #if (progress_bar.extra_label.sprite)
871+ # progress_bar.extra_label.sprite.SetOpacity(0);
872+}
873+
874+fun remove_fsck_from_queue (index) {
875+ # Free memory which was previously allocated for
876+ # device and progress
877+ global.fsck_queue[index].device = NULL;
878+ global.fsck_queue[index].progress = NULL;
879+
880+ # Decrease the queue counter
881+ global.fsck_queue.counter--;
882+
883+ # See if there are other processes in the queue
884+ # if not, clear the extra_label
885+ on_queued_fsck_completed ();
886+}
887+
888+fun on_fsck_completed () {
889+ # We have moved on to tracking the next fsck
890+ increase_current_fsck_count ();
891+
892+ if (!is_progress_label_available ())
893+ return;
894+
895+ if (!is_queue_empty ())
896+ return;
897+
898+ # Hide the progress label
899+ if (progress_label.sprite)
900+ progress_label.sprite.SetOpacity (0);
901+
902+ # Clear the queue
903+ clear_queue ();
904+
905+ # Clear the fsck counter
906+ clear_fsck_count ();
907+}
908+
909+# Update an fsck process that we keep track of in the queue
910+fun update_progress_in_queue (index, device, progress) {
911+ # If the fsck is complete, remove it from the queue
912+ if (progress >= 100) {
913+ remove_fsck_from_queue (index);
914+ on_queued_fsck_completed ();
915+ return;
916+ }
917+
918+ global.fsck_queue[index].device = device;
919+ global.fsck_queue[index].progress = progress;
920+
921+}
922+
923+# TODO: Move it to some function
924+# Create an empty queue
925+#init_queue ();
926+
927+
928+#----------------------------------------- FSCK Functions ------------------------------
929+
930+
931+# Either add a new bar for fsck checks or update an existing bar
932+#
933+# NOTE: no more than "progress_bar.max_number" bars are allowed
934+#
935+fun fsck_check (device, progress, status_string) {
936+
937+ # The 1st time this will take place
938+ if (!global.progress_label) {
939+ # Increase the fsck counter
940+ increase_fsck_count ();
941+
942+ # Set up a new label for the check
943+ init_progress_label (device, status_string);
944+ update_progress_label (progress);
945+
946+ return;
947+ }
948+
949+
950+ if (device_has_progress_label (device)) {
951+ # Update the progress of the existing label
952+ update_progress_label (progress);
953+ }
954+ else {
955+ # See if there's already a slot in the queue for the device
956+ local.queue_device_index = queue_look_up_by_device(device);
957+
958+ # See if the progress_label is available
959+ if (progress_label.is_available) {
960+
961+# local.my_string = "available index " + local.available_index + " progress_bar counter is " + progress_bar.counter;
962+# Debug(local.my_string);
963+
964+
965+ # If the fsck check for the device was in the queue, then
966+ # remove it from the queue
967+ if (local.queue_device_index >= 0) {
968+ remove_fsck_from_queue (index);
969+ }
970+ else {
971+ # Increase the fsck counter
972+ increase_fsck_count ();
973+ }
974+
975+# local.my_string += local.message;
976+ #Debug("setting new label for device " + device + " progress " + progress);
977+
978+ # Set up a new label for the check
979+ init_progress_label (device, status_string);
980+ update_progress_label (progress);
981+
982+ }
983+ # If the progress_label is not available
984+ else {
985+
986+ # If the fsck check for the device is already in the queue
987+ # just update its progress in the queue
988+ if (local.queue_device_index >= 0) {
989+ #DebugMedium("Updating queue at " + local.queue_device_index + " for device " + device);
990+ update_progress_in_queue (local.queue_device_index, device, progress);
991+ }
992+ # Otherwise add the check to the queue
993+ else {
994+ #DebugMedium("Adding device " + device + " to queue at " + local.queue_device_index);
995+ add_fsck_to_queue (device, progress);
996+
997+ # Increase the fsck counter
998+ increase_fsck_count ();
999+
1000+ refresh_progress_label ();
1001+ }
1002+
1003+ }
1004+ }
1005+
1006+# if (!is_queue_empty ()) {
1007+# DebugBottom("Extra label for "+ device);
1008+ #}
1009+# else {
1010+# DebugBottom("No extra label for " + device + ". 1st Device in the queue "+ fsck_queue[0].device + " counter = " + global.fsck_queue.counter);
1011+# }
1012+}
1013+
1014+
1015+#-----------------------------------------Update Status stuff --------------------------
1016+#
1017+# The update_status_callback is what we can use to pass plymouth whatever we want so
1018+# as to make use of features which are available only in this program (as opposed to
1019+# being available for any theme for the script plugin).
1020+#
1021+# Example:
1022+#
1023+# Thanks to the current implementation, some scripts can call "plymouth --update=fsck:sda1:40"
1024+# and this program will know that 1) we're performing and fsck check, 2) we're checking sda1,
1025+# 3) the program should set the label progress to 40%
1026+#
1027+# Other features can be easily added by parsing the string that we pass plymouth with "--update"
1028+#
1029+fun update_status_callback (status) {
1030+# Debug(status);
1031+ if (!status) return;
1032+
1033+ string_it = 0;
1034+ update_strings[string_it] = "";
1035+
1036+ for (i=0; (String(status).CharAt(i) != ""); i++) {
1037+ local.temp_char = String(status).CharAt(i);
1038+ if (temp_char != ":")
1039+ update_strings[string_it] += temp_char;
1040+ else
1041+ update_strings[++string_it] = "";
1042+ }
1043+
1044+# my_string = update_strings[0] + " " + update_strings[1] + " " + update_strings[2];
1045+# Debug(my_string);
1046+ # Let's assume that we're dealing with these strings fsck:sda1:40
1047+ if ((string_it >= 2) && (update_strings[0] == "fsck")) {
1048+
1049+ device = update_strings[1];
1050+ progress = update_strings[2];
1051+ status_string[0] = update_strings[3]; # "Checking disk %1$d of %2$d (%3$d %% complete)"
1052+ if (!status_string[0])
1053+ status_string[0] = "Checking disk %1$d of %2$d (%3$d %% complete)";
1054+
1055+ if ((device != "") && (progress != "")) {
1056+ progress = StringToInteger (progress);
1057+
1058+ # Make sure that the fsck_queue is initialised
1059+ if (!global.fsck_queue)
1060+ init_queue ();
1061+
1062+ # Make sure that the fsck counter is initialised
1063+ if (!global.counter)
1064+ init_fsck_count ();
1065+
1066+# if (!global.progress_bar.extra_label.sprite)
1067+# create_extra_fsck_label ();
1068+
1069+ # Keep track of the fsck check
1070+ fsck_check (device, progress, status_string);
1071+ }
1072+
1073+ }
1074+
1075+}
1076+Plymouth.SetUpdateStatusFunction (update_status_callback);
1077+
1078+#-----------------------------------------Display Question stuff -----------------------
1079+
1080+fun question_dialogue_setup (message_label, text_image) {
1081+ #Debug("Question dialog setup");
1082+
1083+ local.field;
1084+ local.content;
1085+ local.margin;
1086+
1087+ field.image = LoadScaleImage (question_field_filename);
1088+ content = Sprite ();
1089+ bullet_image = LoadScaleImage (progress_dot_off_filename);
1090+ margin = bullet_image.GetWidth() / 2;
1091+
1092+ # Hide the normal labels
1093+ prompt_active = 1;
1094+ if (message_notification[1].sprite) hide_message (1);
1095+
1096+ # Set the prompt label
1097+ label = get_message_label(message_label, 0, 1);
1098+ label.z = 10000;
1099+
1100+ setup_message (message_label, label.x, label.y, label.z, 2);
1101+ show_message (2);
1102+
1103+ # Set up the text field which contains the contents
1104+ field.sprite = Sprite ();
1105+ field.sprite.SetImage (field.image);
1106+
1107+ # Centre the box horizontally
1108+ field.x = Window.GetX () + Window.GetWidth () / 2 - field.image.GetWidth () / 2;
1109+ content_x = field.x + margin;
1110+
1111+ # Put the field below the second label.
1112+ field.y = message_notification[2].y + label.height;
1113+ content_y = field.y + field.image.GetHeight () / 2 - text_image.GetHeight () / 2;
1114+
1115+ #Debug ("field x = " + field.x + ", y = " + field.y);
1116+ field.z = 10000;
1117+ field.sprite.SetX (field.x);
1118+ field.sprite.SetY (field.y);
1119+ field.sprite.SetZ (field.z);
1120+
1121+ #Debug ("content_x = " + content_x + " content_y = " + content_y);
1122+ content_z = field.z + 1;
1123+ content.SetPosition (content_x, content_y, content_z);
1124+
1125+ global.question_dialogue = local;
1126+}
1127+
1128+# The callback function is called when the display should display a question dialogue.
1129+# First arg is prompt string, the second is the field contents.
1130+fun display_question_callback (prompt, contents) {
1131+ global.status = "question";
1132+ #Debug ("Reply: " + contents);
1133+
1134+ textImage = ImageToText(contents);
1135+ if (!global.question_dialogue) {
1136+ question_dialogue_setup(prompt, textImage);
1137+ }
1138+
1139+ margin = global.question_dialogue.margin;
1140+ fieldWidth = global.question_dialogue.field.image.GetWidth ();
1141+ for (i = 0; ( (textImage.GetWidth () + 2 * margin ) > fieldWidth ); i++) {
1142+ textImage = ImageToText(StringCopy (contents, i, StringLength (contents)));
1143+ }
1144+
1145+ global.question_dialogue.content.SetImage (textImage);
1146+}
1147+
1148+
1149+Plymouth.SetDisplayQuestionFunction (display_question_callback);
1150+
1151+#-----------------------------------------Refresh stuff --------------------------------
1152+#
1153+# Calling Plymouth.SetRefreshFunction with a function will set that function to be
1154+# called up to 50 times every second, e.g.
1155+#
1156+# NOTE: if a refresh function is not set, Plymouth doesn't seem to be able to update
1157+# the screen correctly
1158+#
1159+fun refresh_callback ()
1160+{
1161+ draw_logo ();
1162+}
1163+Plymouth.SetRefreshFunction (refresh_callback);
1164+
1165+
1166+#-----------------------------------------Display Normal stuff -----------------------
1167+#
1168+# The callback function is called when the display should return to normal
1169+fun display_normal_callback ()
1170+{
1171+ global.status = "normal";
1172+ if (global.password_dialogue) {
1173+ password_dialogue_opacity (0);
1174+ global.password_dialogue = NULL;
1175+ if (message_notification[2].sprite) hide_message(2);
1176+ prompt_active = 0;
1177+ }
1178+ if (global.question_dialogue) {
1179+ question_dialogue_opacity (0);
1180+ global.question_dialogue = NULL;
1181+ if (message_notification[2].sprite) hide_message(2);
1182+ prompt_active = 0;
1183+ }
1184+
1185+ if (message_notification[1].sprite) show_message (1);
1186+
1187+}
1188+
1189+Plymouth.SetDisplayNormalFunction (display_normal_callback);
1190+
1191+
1192+#----------------------------------------- Quit --------------------------------
1193+
1194+# TODO: Maybe we should also hide any other dialog
1195+# Show the logo and make the progress indicator look full when on exit
1196+fun quit_callback ()
1197+{
1198+ logo.sprite.SetOpacity (1);
1199+ switch_on_bullets ();
1200+}
1201+
1202+Plymouth.SetQuitFunction(quit_callback);
01203
=== added file 'debian/patches/use-upstart-private-socket.patch'
--- debian/patches/use-upstart-private-socket.patch 1970-01-01 00:00:00 +0000
+++ debian/patches/use-upstart-private-socket.patch 2014-03-14 10:43:52 +0000
@@ -0,0 +1,198 @@
1Description: use private upstart socket to start earlier
2Author: Dimitri John Ledkov <xnox@ubuntu.com>
3
4--- a/src/upstart-bridge/ply-upstart-monitor.c
5+++ b/src/upstart-bridge/ply-upstart-monitor.c
6@@ -46,7 +46,6 @@
7 struct _ply_upstart_monitor
8 {
9 DBusConnection *connection;
10- char *owner;
11 ply_event_loop_t *loop;
12 ply_hashtable_t *jobs;
13 ply_hashtable_t *all_instances;
14@@ -74,7 +73,8 @@
15 uint32_t call_failed : 1;
16 } ply_upstart_monitor_instance_t;
17
18-#define UPSTART_SERVICE "com.ubuntu.Upstart"
19+#define UPSTART_SERVICE NULL
20+#define DBUS_ADDRESS_UPSTART "unix:abstract=/com/ubuntu/upstart"
21 #define UPSTART_PATH "/com/ubuntu/Upstart"
22 #define UPSTART_INTERFACE_0_6 "com.ubuntu.Upstart0_6"
23 #define UPSTART_INTERFACE_0_6_JOB "com.ubuntu.Upstart0_6.Job"
24@@ -579,82 +579,6 @@
25 dbus_message_unref (reply);
26 }
27
28-static void
29-on_get_name_owner_finished (DBusPendingCall *call,
30- ply_upstart_monitor_t *monitor)
31-{
32- DBusMessage *reply, *message;
33- DBusError error;
34- const char *owner;
35-
36- assert (call != NULL);
37- assert (monitor != NULL);
38-
39- reply = dbus_pending_call_steal_reply (call);
40- if (reply == NULL)
41- return;
42- if (dbus_message_get_type (reply) != DBUS_MESSAGE_TYPE_METHOD_RETURN)
43- goto out;
44-
45- dbus_error_init (&error);
46- dbus_message_get_args (reply, &error,
47- DBUS_TYPE_STRING, &owner,
48- DBUS_TYPE_INVALID);
49- if (dbus_error_is_set (&error))
50- goto out;
51- dbus_error_free (&error);
52-
53- ply_trace ("owner = '%s'", owner);
54-
55- free (monitor->owner);
56- monitor->owner = strdup (owner);
57-
58- ply_trace ("calling GetAllJobs");
59- message = dbus_message_new_method_call (UPSTART_SERVICE, UPSTART_PATH,
60- UPSTART_INTERFACE_0_6,
61- "GetAllJobs");
62- dbus_connection_send_with_reply (monitor->connection, message, &call, -1);
63- dbus_message_unref (message);
64- if (call != NULL)
65- dbus_pending_call_set_notify (call,
66- (DBusPendingCallNotifyFunction)
67- on_get_all_jobs_finished,
68- monitor, NULL);
69-
70-out:
71- dbus_message_unref (reply);
72-}
73-
74-static DBusHandlerResult
75-name_owner_changed_handler (DBusConnection *connection,
76- DBusMessage *message,
77- ply_upstart_monitor_t *monitor)
78-{
79- DBusError error;
80- const char *name, *old_owner, *new_owner;
81-
82- assert (connection != NULL);
83- assert (message != NULL);
84- assert (monitor != NULL);
85-
86- dbus_error_init (&error);
87- if (dbus_message_get_args (message, &error,
88- DBUS_TYPE_STRING, &name,
89- DBUS_TYPE_STRING, &old_owner,
90- DBUS_TYPE_STRING, &new_owner,
91- DBUS_TYPE_INVALID) &&
92- strcmp (name, UPSTART_SERVICE) == 0)
93- {
94- if (new_owner)
95- ply_trace ("owner changed from '%s' to '%s'", old_owner, new_owner);
96- else
97- ply_trace ("owner left bus");
98- free (monitor->owner);
99- monitor->owner = new_owner ? strdup (new_owner) : NULL;
100- }
101-
102- return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; /* let other handlers try */
103-}
104
105 static DBusHandlerResult
106 job_added_handler (DBusConnection *connection,
107@@ -856,12 +780,6 @@
108 if (path == NULL)
109 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
110
111- if (dbus_message_is_signal (message, DBUS_INTERFACE_DBUS,
112- "NameOwnerChanged") &&
113- dbus_message_has_path (message, DBUS_PATH_DBUS) &&
114- dbus_message_has_sender (message, DBUS_SERVICE_DBUS))
115- return name_owner_changed_handler (connection, message, monitor);
116-
117 if (dbus_message_is_signal (message, UPSTART_INTERFACE_0_6,
118 "JobAdded"))
119 return job_added_handler (connection, message, monitor);
120@@ -899,9 +817,7 @@
121 DBusError error;
122 DBusConnection *connection;
123 ply_upstart_monitor_t *monitor;
124- char *rule;
125 DBusMessage *message;
126- const char *monitor_service = UPSTART_SERVICE;
127 DBusPendingCall *call;
128
129 dbus_error_init (&error);
130@@ -909,7 +825,7 @@
131 /* Get a connection to the system bus and set it up to listen for messages
132 * from Upstart.
133 */
134- connection = dbus_bus_get (DBUS_BUS_SYSTEM, &error);
135+ connection = dbus_connection_open (DBUS_ADDRESS_UPSTART, &error);
136 if (connection == NULL)
137 {
138 ply_error ("unable to connect to system bus: %s", error.message);
139@@ -938,52 +854,17 @@
140 return NULL;
141 }
142
143- asprintf (&rule, "type='%s',sender='%s',path='%s',"
144- "interface='%s',member='%s',arg0='%s'",
145- "signal", DBUS_SERVICE_DBUS, DBUS_PATH_DBUS,
146- DBUS_INTERFACE_DBUS, "NameOwnerChanged", UPSTART_SERVICE);
147- dbus_bus_add_match (connection, rule, &error);
148- free (rule);
149- if (dbus_error_is_set (&error))
150- {
151- ply_error ("unable to add match rule to system bus connection: %s",
152- error.message);
153- ply_upstart_monitor_free (monitor);
154- dbus_error_free (&error);
155- return NULL;
156- }
157-
158- asprintf (&rule, "type='%s',sender='%s'", "signal", UPSTART_SERVICE);
159- dbus_bus_add_match (connection, rule, &error);
160- free (rule);
161- if (dbus_error_is_set (&error))
162- {
163- ply_error ("unable to add match rule to system bus connection: %s",
164- error.message);
165- ply_upstart_monitor_free (monitor);
166- dbus_error_free (&error);
167- return NULL;
168- }
169-
170- /* Start the state machine going: find out the current owner of the
171- * well-known Upstart name.
172- * Ignore errors: the worst case is that we don't get any messages back
173- * and our state machine does nothing.
174- */
175- ply_trace ("calling GetNameOwner");
176- message = dbus_message_new_method_call (DBUS_SERVICE_DBUS, DBUS_PATH_DBUS,
177- DBUS_INTERFACE_DBUS, "GetNameOwner");
178- dbus_message_append_args (message,
179- DBUS_TYPE_STRING, &monitor_service,
180- DBUS_TYPE_INVALID);
181- dbus_connection_send_with_reply (connection, message, &call, -1);
182+ ply_trace ("calling GetAllJobs");
183+ message = dbus_message_new_method_call (UPSTART_SERVICE, UPSTART_PATH,
184+ UPSTART_INTERFACE_0_6,
185+ "GetAllJobs");
186+ dbus_connection_send_with_reply (monitor->connection, message, &call, -1);
187 dbus_message_unref (message);
188 if (call != NULL)
189 dbus_pending_call_set_notify (call,
190 (DBusPendingCallNotifyFunction)
191- on_get_name_owner_finished,
192- monitor,
193- NULL);
194+ on_get_all_jobs_finished,
195+ monitor, NULL);
196
197 if (loop != NULL)
198 ply_upstart_monitor_connect_to_event_loop (monitor, loop);
0199
=== modified file 'debian/plymouth-theme-ubuntu-logo.postinst'
--- debian/plymouth-theme-ubuntu-logo.postinst 2011-04-15 13:35:04 +0000
+++ debian/plymouth-theme-ubuntu-logo.postinst 2014-03-14 10:43:52 +0000
@@ -24,6 +24,12 @@
24 --slave /lib/plymouth/themes/default.grub default.plymouth.grub \24 --slave /lib/plymouth/themes/default.grub default.plymouth.grub \
25 /lib/plymouth/themes/ubuntu-logo/ubuntu-logo.grub25 /lib/plymouth/themes/ubuntu-logo/ubuntu-logo.grub
2626
27 update-alternatives \
28 --install /lib/plymouth/themes/default.plymouth default.plymouth \
29 /lib/plymouth/themes/ubuntu-logo/ubuntu-logo-scale-2.plymouth 99 \
30 --slave /lib/plymouth/themes/default.grub default.plymouth.grub \
31 /lib/plymouth/themes/ubuntu-logo/ubuntu-logo.grub
32
27 if which update-initramfs >/dev/null 2>&133 if which update-initramfs >/dev/null 2>&1
28 then34 then
29 update-initramfs -u35 update-initramfs -u
3036
=== modified file 'debian/plymouth-theme-ubuntu-logo.prerm'
--- debian/plymouth-theme-ubuntu-logo.prerm 2011-02-09 20:41:53 +0000
+++ debian/plymouth-theme-ubuntu-logo.prerm 2014-03-14 10:43:52 +0000
@@ -5,6 +5,8 @@
5if [ "x$1" = xremove ]; then5if [ "x$1" = xremove ]; then
6 update-alternatives \6 update-alternatives \
7 --remove default.plymouth /lib/plymouth/themes/ubuntu-logo/ubuntu-logo.plymouth7 --remove default.plymouth /lib/plymouth/themes/ubuntu-logo/ubuntu-logo.plymouth
8 update-alternatives \
9 --remove default.plymouth /lib/plymouth/themes/ubuntu-logo/ubuntu-logo-scale-2.plymouth
8fi10fi
911
10#DEBHELPER#12#DEBHELPER#
1113
=== modified file 'debian/plymouth.plymouth-upstart-bridge.upstart'
--- debian/plymouth.plymouth-upstart-bridge.upstart 2012-09-07 18:03:39 +0000
+++ debian/plymouth.plymouth-upstart-bridge.upstart 2014-03-14 10:43:52 +0000
@@ -5,9 +5,12 @@
55
6description "bridge from Upstart state changes to Plymouth"6description "bridge from Upstart state changes to Plymouth"
77
8start on (started dbus8respawn
9
10start on (startup
9 or runlevel [06])11 or runlevel [06])
10stop on stopping plymouth12stop on (stopping plymouth
13 or stopping plymouth-shutdown)
1114
12console output15console output
1316
1417
=== modified file 'src/upstart-bridge/ply-upstart-monitor.c'
--- src/upstart-bridge/ply-upstart-monitor.c 2011-03-12 22:54:53 +0000
+++ src/upstart-bridge/ply-upstart-monitor.c 2014-03-14 10:43:52 +0000
@@ -46,7 +46,6 @@
46struct _ply_upstart_monitor46struct _ply_upstart_monitor
47{47{
48 DBusConnection *connection;48 DBusConnection *connection;
49 char *owner;
50 ply_event_loop_t *loop;49 ply_event_loop_t *loop;
51 ply_hashtable_t *jobs;50 ply_hashtable_t *jobs;
52 ply_hashtable_t *all_instances;51 ply_hashtable_t *all_instances;
@@ -74,7 +73,8 @@
74 uint32_t call_failed : 1;73 uint32_t call_failed : 1;
75} ply_upstart_monitor_instance_t;74} ply_upstart_monitor_instance_t;
7675
77#define UPSTART_SERVICE "com.ubuntu.Upstart"76#define UPSTART_SERVICE NULL
77#define DBUS_ADDRESS_UPSTART "unix:abstract=/com/ubuntu/upstart"
78#define UPSTART_PATH "/com/ubuntu/Upstart"78#define UPSTART_PATH "/com/ubuntu/Upstart"
79#define UPSTART_INTERFACE_0_6 "com.ubuntu.Upstart0_6"79#define UPSTART_INTERFACE_0_6 "com.ubuntu.Upstart0_6"
80#define UPSTART_INTERFACE_0_6_JOB "com.ubuntu.Upstart0_6.Job"80#define UPSTART_INTERFACE_0_6_JOB "com.ubuntu.Upstart0_6.Job"
@@ -273,7 +273,7 @@
273 DBUS_TYPE_STRING)273 DBUS_TYPE_STRING)
274 goto next_item;274 goto next_item;
275 dbus_message_iter_get_basic (&variant_iter, &description);275 dbus_message_iter_get_basic (&variant_iter, &description);
276 if (description != NULL)276 if (description != NULL && description[0])
277 {277 {
278 ply_trace ("description = '%s'", description);278 ply_trace ("description = '%s'", description);
279 job->properties.description = strdup (description);279 job->properties.description = strdup (description);
@@ -579,82 +579,6 @@
579 dbus_message_unref (reply);579 dbus_message_unref (reply);
580}580}
581581
582static void
583on_get_name_owner_finished (DBusPendingCall *call,
584 ply_upstart_monitor_t *monitor)
585{
586 DBusMessage *reply, *message;
587 DBusError error;
588 const char *owner;
589
590 assert (call != NULL);
591 assert (monitor != NULL);
592
593 reply = dbus_pending_call_steal_reply (call);
594 if (reply == NULL)
595 return;
596 if (dbus_message_get_type (reply) != DBUS_MESSAGE_TYPE_METHOD_RETURN)
597 goto out;
598
599 dbus_error_init (&error);
600 dbus_message_get_args (reply, &error,
601 DBUS_TYPE_STRING, &owner,
602 DBUS_TYPE_INVALID);
603 if (dbus_error_is_set (&error))
604 goto out;
605 dbus_error_free (&error);
606
607 ply_trace ("owner = '%s'", owner);
608
609 free (monitor->owner);
610 monitor->owner = strdup (owner);
611
612 ply_trace ("calling GetAllJobs");
613 message = dbus_message_new_method_call (UPSTART_SERVICE, UPSTART_PATH,
614 UPSTART_INTERFACE_0_6,
615 "GetAllJobs");
616 dbus_connection_send_with_reply (monitor->connection, message, &call, -1);
617 dbus_message_unref (message);
618 if (call != NULL)
619 dbus_pending_call_set_notify (call,
620 (DBusPendingCallNotifyFunction)
621 on_get_all_jobs_finished,
622 monitor, NULL);
623
624out:
625 dbus_message_unref (reply);
626}
627
628static DBusHandlerResult
629name_owner_changed_handler (DBusConnection *connection,
630 DBusMessage *message,
631 ply_upstart_monitor_t *monitor)
632{
633 DBusError error;
634 const char *name, *old_owner, *new_owner;
635
636 assert (connection != NULL);
637 assert (message != NULL);
638 assert (monitor != NULL);
639
640 dbus_error_init (&error);
641 if (dbus_message_get_args (message, &error,
642 DBUS_TYPE_STRING, &name,
643 DBUS_TYPE_STRING, &old_owner,
644 DBUS_TYPE_STRING, &new_owner,
645 DBUS_TYPE_INVALID) &&
646 strcmp (name, UPSTART_SERVICE) == 0)
647 {
648 if (new_owner)
649 ply_trace ("owner changed from '%s' to '%s'", old_owner, new_owner);
650 else
651 ply_trace ("owner left bus");
652 free (monitor->owner);
653 monitor->owner = new_owner ? strdup (new_owner) : NULL;
654 }
655
656 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; /* let other handlers try */
657}
658582
659static DBusHandlerResult583static DBusHandlerResult
660job_added_handler (DBusConnection *connection,584job_added_handler (DBusConnection *connection,
@@ -856,12 +780,6 @@
856 if (path == NULL)780 if (path == NULL)
857 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;781 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
858782
859 if (dbus_message_is_signal (message, DBUS_INTERFACE_DBUS,
860 "NameOwnerChanged") &&
861 dbus_message_has_path (message, DBUS_PATH_DBUS) &&
862 dbus_message_has_sender (message, DBUS_SERVICE_DBUS))
863 return name_owner_changed_handler (connection, message, monitor);
864
865 if (dbus_message_is_signal (message, UPSTART_INTERFACE_0_6,783 if (dbus_message_is_signal (message, UPSTART_INTERFACE_0_6,
866 "JobAdded"))784 "JobAdded"))
867 return job_added_handler (connection, message, monitor);785 return job_added_handler (connection, message, monitor);
@@ -899,9 +817,7 @@
899 DBusError error;817 DBusError error;
900 DBusConnection *connection;818 DBusConnection *connection;
901 ply_upstart_monitor_t *monitor;819 ply_upstart_monitor_t *monitor;
902 char *rule;
903 DBusMessage *message;820 DBusMessage *message;
904 const char *monitor_service = UPSTART_SERVICE;
905 DBusPendingCall *call;821 DBusPendingCall *call;
906822
907 dbus_error_init (&error);823 dbus_error_init (&error);
@@ -909,7 +825,7 @@
909 /* Get a connection to the system bus and set it up to listen for messages825 /* Get a connection to the system bus and set it up to listen for messages
910 * from Upstart.826 * from Upstart.
911 */827 */
912 connection = dbus_bus_get (DBUS_BUS_SYSTEM, &error);828 connection = dbus_connection_open (DBUS_ADDRESS_UPSTART, &error);
913 if (connection == NULL)829 if (connection == NULL)
914 {830 {
915 ply_error ("unable to connect to system bus: %s", error.message);831 ply_error ("unable to connect to system bus: %s", error.message);
@@ -938,52 +854,17 @@
938 return NULL;854 return NULL;
939 }855 }
940856
941 asprintf (&rule, "type='%s',sender='%s',path='%s',"857 ply_trace ("calling GetAllJobs");
942 "interface='%s',member='%s',arg0='%s'",858 message = dbus_message_new_method_call (UPSTART_SERVICE, UPSTART_PATH,
943 "signal", DBUS_SERVICE_DBUS, DBUS_PATH_DBUS,859 UPSTART_INTERFACE_0_6,
944 DBUS_INTERFACE_DBUS, "NameOwnerChanged", UPSTART_SERVICE);860 "GetAllJobs");
945 dbus_bus_add_match (connection, rule, &error);861 dbus_connection_send_with_reply (monitor->connection, message, &call, -1);
946 free (rule);
947 if (dbus_error_is_set (&error))
948 {
949 ply_error ("unable to add match rule to system bus connection: %s",
950 error.message);
951 ply_upstart_monitor_free (monitor);
952 dbus_error_free (&error);
953 return NULL;
954 }
955
956 asprintf (&rule, "type='%s',sender='%s'", "signal", UPSTART_SERVICE);
957 dbus_bus_add_match (connection, rule, &error);
958 free (rule);
959 if (dbus_error_is_set (&error))
960 {
961 ply_error ("unable to add match rule to system bus connection: %s",
962 error.message);
963 ply_upstart_monitor_free (monitor);
964 dbus_error_free (&error);
965 return NULL;
966 }
967
968 /* Start the state machine going: find out the current owner of the
969 * well-known Upstart name.
970 * Ignore errors: the worst case is that we don't get any messages back
971 * and our state machine does nothing.
972 */
973 ply_trace ("calling GetNameOwner");
974 message = dbus_message_new_method_call (DBUS_SERVICE_DBUS, DBUS_PATH_DBUS,
975 DBUS_INTERFACE_DBUS, "GetNameOwner");
976 dbus_message_append_args (message,
977 DBUS_TYPE_STRING, &monitor_service,
978 DBUS_TYPE_INVALID);
979 dbus_connection_send_with_reply (connection, message, &call, -1);
980 dbus_message_unref (message);862 dbus_message_unref (message);
981 if (call != NULL)863 if (call != NULL)
982 dbus_pending_call_set_notify (call,864 dbus_pending_call_set_notify (call,
983 (DBusPendingCallNotifyFunction)865 (DBusPendingCallNotifyFunction)
984 on_get_name_owner_finished,866 on_get_all_jobs_finished,
985 monitor,867 monitor, NULL);
986 NULL);
987868
988 if (loop != NULL)869 if (loop != NULL)
989 ply_upstart_monitor_connect_to_event_loop (monitor, loop);870 ply_upstart_monitor_connect_to_event_loop (monitor, loop);
990871
=== modified file 'src/upstart-bridge/plymouth-upstart-bridge.c'
--- src/upstart-bridge/plymouth-upstart-bridge.c 2011-03-12 22:54:53 +0000
+++ src/upstart-bridge/plymouth-upstart-bridge.c 2014-03-14 10:43:52 +0000
@@ -307,7 +307,9 @@
307 if (should_be_verbose && !ply_is_tracing ())307 if (should_be_verbose && !ply_is_tracing ())
308 ply_toggle_tracing ();308 ply_toggle_tracing ();
309309
310 setupterm (NULL, STDOUT_FILENO, NULL);310 /* Don't bail on dummy/hardcopy terminals */
311 int errret=0;
312 setupterm (NULL, STDOUT_FILENO, &errret);
311313
312 is_connected = ply_boot_client_connect (state.client,314 is_connected = ply_boot_client_connect (state.client,
313 (ply_boot_client_disconnect_handler_t)315 (ply_boot_client_disconnect_handler_t)
314316
=== modified file 'themes/ubuntu-logo/Makefile.am'
--- themes/ubuntu-logo/Makefile.am 2011-04-15 13:35:04 +0000
+++ themes/ubuntu-logo/Makefile.am 2014-03-14 10:43:52 +0000
@@ -1,6 +1,7 @@
1themedir = $(datadir)/plymouth/themes/ubuntu-logo1themedir = $(datadir)/plymouth/themes/ubuntu-logo
2nodist_theme_DATA = ubuntu-logo.plymouth2nodist_theme_DATA = ubuntu-logo.plymouth ubuntu-logo-scale-2.plymouth
3dist_theme_DATA = ubuntu-logo.script \3dist_theme_DATA = ubuntu-logo.script \
4 ubuntu-logo-scale-2.script \
4 ubuntu-logo.grub \5 ubuntu-logo.grub \
5 ubuntu_logo.png \6 ubuntu_logo.png \
6 ubuntu_logo16.png \7 ubuntu_logo16.png \
@@ -13,11 +14,23 @@
1314
1415
1516
16MAINTAINERCLEANFILES = Makefile.in ubuntu-logo.plymouth17MAINTAINERCLEANFILES = Makefile.in ubuntu-logo.plymouth ubuntu-logo-scale-2.plymouth ubuntu-logo.script ubuntu-logo-scale-2.script
17CLEANFILES = ubuntu-logo.plymouth18CLEANFILES = ubuntu-logo.plymouth ubuntu-logo-scale-2.plymouth ubuntu-logo.script ubuntu-logo-scale-2.script
1819
19ubuntu-logo.plymouth: $(srcdir)/ubuntu-logo.plymouth.in20ubuntu-logo.plymouth: $(srcdir)/ubuntu-logo.plymouth.in
20 sed -e 's,[@]PLYMOUTH_THEME_PATH[@],$(PLYMOUTH_THEME_PATH),g' \21 sed -e 's,[@]PLYMOUTH_THEME_PATH[@],$(PLYMOUTH_THEME_PATH),g;s,[@]EXTRA_NAME[@],,g;s,[@]SCRIPT_NAME[@],ubuntu-logo,g' \
21 $(srcdir)/ubuntu-logo.plymouth.in > ubuntu-logo.plymouth22 $(srcdir)/ubuntu-logo.plymouth.in > ubuntu-logo.plymouth
2223
23EXTRA_DIST = ubuntu-logo.plymouth.in24ubuntu-logo-scale-2.plymouth: $(srcdir)/ubuntu-logo.plymouth.in
25 sed -e 's,[@]PLYMOUTH_THEME_PATH[@],$(PLYMOUTH_THEME_PATH),g;s,[@]EXTRA_NAME[@],(Scale x2),g;s,[@]SCRIPT_NAME[@],ubuntu-logo-scale-2,g' \
26 $(srcdir)/ubuntu-logo.plymouth.in > ubuntu-logo-scale-2.plymouth
27
28ubuntu-logo.script: $(srcdir)/ubuntu-logo.script.in
29 sed -e 's,[@]SCALEFACTOR[@],1,g' \
30 $(srcdir)/ubuntu-logo.script.in > ubuntu-logo.script
31
32ubuntu-logo-scale-2.script: $(srcdir)/ubuntu-logo.script.in
33 sed -e 's,[@]SCALEFACTOR[@],2,g' \
34 $(srcdir)/ubuntu-logo.script.in > ubuntu-logo-scale-2.script
35
36EXTRA_DIST = ubuntu-logo.plymouth.in ubuntu-logo.script.in
2437
=== modified file 'themes/ubuntu-logo/ubuntu-logo.plymouth.in'
--- themes/ubuntu-logo/ubuntu-logo.plymouth.in 2009-12-07 19:55:24 +0000
+++ themes/ubuntu-logo/ubuntu-logo.plymouth.in 2014-03-14 10:43:52 +0000
@@ -1,8 +1,8 @@
1[Plymouth Theme]1[Plymouth Theme]
2Name=Ubuntu Logo2Name=Ubuntu Logo @EXTRA_NAME@
3Description=A theme that features a blank background with a logo.3Description=A theme that features a blank background with a logo.
4ModuleName=script4ModuleName=script
55
6[script]6[script]
7ImageDir=@PLYMOUTH_THEME_PATH@/ubuntu-logo7ImageDir=@PLYMOUTH_THEME_PATH@/ubuntu-logo
8ScriptFile=@PLYMOUTH_THEME_PATH@/ubuntu-logo/ubuntu-logo.script8ScriptFile=@PLYMOUTH_THEME_PATH@/ubuntu-logo/@SCRIPT_NAME@.script
99
=== renamed file 'themes/ubuntu-logo/ubuntu-logo.script' => 'themes/ubuntu-logo/ubuntu-logo.script.in'
--- themes/ubuntu-logo/ubuntu-logo.script 2013-02-14 00:56:49 +0000
+++ themes/ubuntu-logo/ubuntu-logo.script.in 2014-03-14 10:43:52 +0000
@@ -46,12 +46,27 @@
46debugsprite_bottom = Sprite();46debugsprite_bottom = Sprite();
47debugsprite_medium = Sprite();47debugsprite_medium = Sprite();
4848
49# Ubuntu Font
50ubuntufont = "Ubuntu 11";
51ubuntualignment = "center";
52
53# Scale factor
54scalefactor = @SCALEFACTOR@;
55
49# are we currently prompting for a password?56# are we currently prompting for a password?
50prompt_active = 0;57prompt_active = 0;
5158
59# Generic scalable image loader
60fun LoadScaleImage (imagepath) {
61 image = Image (imagepath);
62 image = image.Scale (image.GetWidth() * scalefactor, image.GetHeight() * scalefactor);
63 return image;
64}
65
52# General purpose function to create text66# General purpose function to create text
53fun WriteText (text, colour) {67fun WriteText (text, colour) {
54 image = Image.Text (text, colour.red, colour.green, colour.blue);68 image = Image.Text (text, colour.red, colour.green, colour.blue, color.alpha, ubuntufont, ubuntualignment);
69 image = image.Scale (image.GetWidth() * scalefactor, image.GetHeight() * scalefactor);
55 return image;70 return image;
56}71}
5772
@@ -184,7 +199,7 @@
184 question_field_filename = "password_field.png";199 question_field_filename = "password_field.png";
185}200}
186201
187logo.image = Image (logo_filename);202logo.image = LoadScaleImage (logo_filename);
188logo.sprite = Sprite ();203logo.sprite = Sprite ();
189logo.sprite.SetImage (logo.image);204logo.sprite.SetImage (logo.image);
190logo.width = logo.image.GetWidth ();205logo.width = logo.image.GetWidth ();
@@ -206,8 +221,8 @@
206221
207status = "normal";222status = "normal";
208223
209progress_indicator.bullet_off = Image (progress_dot_off_filename);224progress_indicator.bullet_off = LoadScaleImage (progress_dot_off_filename);
210progress_indicator.bullet_on = Image (progress_dot_on_filename);225progress_indicator.bullet_on = LoadScaleImage (progress_dot_on_filename);
211progress_indicator.bullet_width = progress_indicator.bullet_off.GetWidth ();226progress_indicator.bullet_width = progress_indicator.bullet_off.GetWidth ();
212progress_indicator.bullet_height = progress_indicator.bullet_off.GetHeight ();227progress_indicator.bullet_height = progress_indicator.bullet_off.GetHeight ();
213progress_indicator.bullet_hspacing = progress_indicator.bullet_width * 1.1;228progress_indicator.bullet_hspacing = progress_indicator.bullet_width * 1.1;
@@ -509,9 +524,8 @@
509 524
510 local.entry;525 local.entry;
511 local.bullet_image;526 local.bullet_image;
512 527 bullet_image = LoadScaleImage (progress_dot_off_filename);
513 bullet_image = Image (progress_dot_off_filename);528 entry.image = LoadScaleImage (password_field_filename);
514 entry.image = Image (password_field_filename);
515 529
516 # Hide the normal labels530 # Hide the normal labels
517 prompt_active = 1;531 prompt_active = 1;
@@ -1010,9 +1024,9 @@
1010 local.content;1024 local.content;
1011 local.margin;1025 local.margin;
1012 1026
1013 field.image = Image (question_field_filename);1027 field.image = LoadScaleImage (question_field_filename);
1014 content = Sprite (); 1028 content = Sprite ();
1015 bullet_image = Image (progress_dot_off_filename);1029 bullet_image = LoadScaleImage (progress_dot_off_filename);
1016 margin = bullet_image.GetWidth() / 2;1030 margin = bullet_image.GetWidth() / 2;
1017 1031
1018 # Hide the normal labels1032 # Hide the normal labels

Subscribers

People subscribed via source and target branches