Merge lp:~mvo/click/native-dbus into lp:click/devel

Proposed by Michael Vogt on 2015-12-09
Status: Work in progress
Proposed branch: lp:~mvo/click/native-dbus
Merge into: lp:click/devel
Diff against target: 779 lines (+543/-17) (has conflicts)
15 files modified
.bzrignore (+3/-0)
click/commands/unregister.py (+15/-5)
click/install.py (+32/-0)
click/tests/test_install.py (+2/-0)
configure.ac (+18/-0)
debian/click.install (+2/-0)
debian/libclick-0.4-0.symbols (+7/-0)
lib/click/Makefile.am (+39/-9)
lib/click/click.sym (+7/-0)
lib/click/com.ubuntu.Click.conf (+23/-0)
lib/click/com.ubuntu.Click.service.in (+4/-0)
lib/click/com.ubuntu.Click.xml (+21/-0)
lib/click/dbus-interface.vala (+66/-0)
lib/click/dbus-service.vala (+297/-0)
lib/click/valac-wrapper.in (+7/-3)
Text conflict in click/install.py
To merge this branch: bzr merge lp:~mvo/click/native-dbus
Reviewer Review Type Date Requested Status
click hackers 2015-12-09 Pending
Review via email: mp+280071@code.launchpad.net

Description of the change

Native dbus support for click without the need for PK plugin.

To post a comment you must log in.

Unmerged revisions

542. By Michael Vogt on 2014-10-17

click/tests/test_install.py: set CLICK_IN_DBUS_SERVICE in TestClickInstaller

541. By Michael Vogt on 2014-10-17

always pass the full path to the backend

540. By Michael Vogt on 2014-10-17

fix dbus call

539. By Michael Vogt on 2014-10-17

lib/click/Makefile.am: fix pkglibexecdir substitutions

538. By Michael Vogt on 2014-10-17

debian/libclick-0.4-0.symbols: update to include the new symbols

537. By Michael Vogt on 2014-10-17

debian/click.install: include dbus files

536. By Michael Vogt on 2014-10-17

merged lp:click/devel

535. By Michael Vogt on 2014-10-17

click/commands/unregister.py: make unregister use dbus

534. By Michael Vogt on 2014-10-16

use python dbus instead of the generated vala interface to call InstallFiles

533. By Colin Watson on 2014-10-16

First cut at a native D-Bus service for click. Doesn't quite work yet.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file '.bzrignore'
2--- .bzrignore 2014-07-09 12:56:21 +0000
3+++ .bzrignore 2015-12-09 20:26:30 +0000
4@@ -67,6 +67,9 @@
5 lib/click/click.h
6 lib/click/click-0.4.pc
7 lib/click/click-0.4.vapi
8+lib/click/click-dbus-service
9+lib/click/click_dbus_service_vala.stamp
10+lib/click/com.ubuntu.Click.service
11 lib/click/libclick_0_4_la_vala.stamp
12 lib/click/paths.vala
13 lib/click/valac-wrapper
14
15=== modified file 'click/commands/unregister.py'
16--- click/commands/unregister.py 2014-04-03 08:52:02 +0000
17+++ click/commands/unregister.py 2015-12-09 20:26:30 +0000
18@@ -21,6 +21,7 @@
19 import os
20 import sys
21
22+import dbus
23 from gi.repository import Click
24
25
26@@ -38,9 +39,11 @@
27 if len(args) < 1:
28 parser.error("need package name")
29 if os.geteuid() != 0:
30- parser.error(
31- "click unregister must be started as root, since it may need to "
32- "remove packages from disk")
33+ # only root can remove packages for other people
34+ if options.user is not None or options.all_users:
35+ parser.error(
36+ "click unregister must be started as root, since it may "
37+ "need to remove packages from disk")
38 if options.user is None and "SUDO_USER" in os.environ:
39 options.user = os.environ["SUDO_USER"]
40 db = Click.DB()
41@@ -59,7 +62,14 @@
42 (package, old_version, args[1]),
43 file=sys.stderr)
44 sys.exit(1)
45- registry.remove(package)
46- db.maybe_remove(package, old_version)
47+ # send via dbus if we are not root
48+ if os.geteuid() != 0:
49+ bus = dbus.SystemBus()
50+ obj = bus.get_object("com.ubuntu.Click", "/com/ubuntu/Click")
51+ iface = dbus.Interface(obj, "com.ubuntu.Click")
52+ iface.RemovePackage(package, old_version)
53+ else:
54+ registry.remove(package)
55+ db.maybe_remove(package, old_version)
56 # TODO: remove data
57 return 0
58
59=== modified file 'click/install.py'
60--- click/install.py 2015-11-24 13:03:01 +0000
61+++ click/install.py 2015-12-09 20:26:30 +0000
62@@ -42,6 +42,11 @@
63
64 from contextlib import closing
65
66+<<<<<<< TREE
67+=======
68+import apt_pkg
69+import dbus
70+>>>>>>> MERGE-SOURCE
71 from debian.debfile import DebFile as _DebFile
72 from debian.debian_support import Version
73 from gi.repository import Click
74@@ -130,6 +135,15 @@
75 self.force_missing_framework = force_missing_framework
76 self.allow_unauthenticated = allow_unauthenticated
77
78+ @property
79+ def dbus_install_flags(self):
80+ flags = 0
81+ if self.force_missing_framework:
82+ flags |= Click.InstallFlags.FORCE_MISSING_FRAMEWORK
83+ if self.allow_unauthenticated:
84+ flags |= Click.InstallFlags.ALLOW_UNAUTHENTICATED
85+ return flags
86+
87 def _preload_path(self):
88 if "CLICK_PACKAGE_PRELOAD" in os.environ:
89 return os.environ["CLICK_PACKAGE_PRELOAD"]
90@@ -458,7 +472,25 @@
91
92 return package_name, package_version, old_version
93
94+<<<<<<< TREE
95 def install(self, path, user=None, all_users=False, quiet=True):
96+=======
97+ def install(self, path, user=None, all_users=False):
98+ if not all_users and "CLICK_IN_DBUS_SERVICE" not in os.environ:
99+ # we can not use:
100+ # Click.DBusInterface.install_file(path, self.dbus_install_flags)
101+ # here directly because the generated gobject-introspection can
102+ # not be instantiated from python because its a abstract vala
103+ # interface
104+ bus = dbus.SystemBus()
105+ obj = bus.get_object("com.ubuntu.Click", "/com/ubuntu/Click")
106+ iface = dbus.Interface(obj,"com.ubuntu.Click")
107+ # always pass the full path to the backend
108+ abs_path = os.path.abspath(path)
109+ iface.InstallFile(abs_path, self.dbus_install_flags)
110+ return
111+
112+>>>>>>> MERGE-SOURCE
113 package_name, package_version, old_version = self._unpack(
114 path, user=user, all_users=all_users, quiet=quiet)
115
116
117=== modified file 'click/tests/test_install.py'
118--- click/tests/test_install.py 2015-10-15 12:53:30 +0000
119+++ click/tests/test_install.py 2015-12-09 20:26:30 +0000
120@@ -84,6 +84,8 @@
121 # mock signature checks during the tests
122 self.debsig_patcher = mock.patch("click.install.DebsigVerify")
123 self.debsig_patcher.start()
124+ # ensure install does not try to call the dbus
125+ os.environ["CLICK_IN_DBUS_SERVICE"] = "1"
126
127 def tearDown(self):
128 self.debsig_patcher.stop()
129
130=== modified file 'configure.ac'
131--- configure.ac 2014-06-30 16:48:31 +0000
132+++ configure.ac 2015-12-09 20:26:30 +0000
133@@ -93,6 +93,24 @@
134 fi
135 AM_CONDITIONAL([PACKAGEKIT], [test "x$enable_packagekit" = xyes])
136
137+AC_ARG_WITH([dbus-sys-dir],
138+ AS_HELP_STRING([--with-dbus-sys-dir=DIR], [D-Bus system.d directory]))
139+if test "x$with_dbus_sys_dir" != x; then
140+ DBUS_SYS_DIR="$with_dbus_sys_dir"
141+else
142+ DBUS_SYS_DIR="$sysconfdir/dbus-1/system.d"
143+fi
144+AC_SUBST([DBUS_SYS_DIR])
145+
146+AC_ARG_WITH([dbus-services-dir],
147+ AS_HELP_STRING([--with-dbus-services-dir=DIR], [D-Bus system-services directory]))
148+if test "x$with_dbus_services_dir" != x; then
149+ DBUS_SERVICES_DIR="$with_dbus_services_dir"
150+else
151+ DBUS_SERVICES_DIR="$datadir/dbus-1/system-services"
152+fi
153+AC_SUBST([DBUS_SERVICES_DIR])
154+
155 AC_ARG_ENABLE([systemd],
156 AS_HELP_STRING([--disable-systemd], [Disable systemd integration]))
157 AM_CONDITIONAL([INSTALL_SYSTEMD], [test "x$enable_systemd" != xno])
158
159=== modified file 'debian/click.install'
160--- debian/click.install 2014-03-05 16:36:20 +0000
161+++ debian/click.install 2015-12-09 20:26:30 +0000
162@@ -1,7 +1,9 @@
163 etc/click
164+etc/dbus-1/system.d/
165 etc/init
166 lib/systemd
167 usr/bin/click
168 usr/lib/*/click
169 usr/lib/systemd
170 usr/share/upstart
171+usr/share/dbus-1/system-services
172\ No newline at end of file
173
174=== modified file 'debian/libclick-0.4-0.symbols'
175--- debian/libclick-0.4-0.symbols 2014-03-31 10:50:20 +0000
176+++ debian/libclick-0.4-0.symbols 2015-12-09 20:26:30 +0000
177@@ -18,6 +18,12 @@
178 click_db_maybe_remove@Base 0.4.17
179 click_db_new@Base 0.4.17
180 click_db_read@Base 0.4.17
181+ click_dbus_error_quark@Base 0.4.34
182+ click_dbus_interface_get_type@Base 0.4.34
183+ click_dbus_interface_install_file@Base 0.4.34
184+ click_dbus_interface_proxy_get_type@Base 0.4.34
185+ click_dbus_interface_register_object@Base 0.4.34
186+ click_dbus_interface_remove_package@Base 0.4.34
187 click_dir_get_type@Base 0.4.17
188 click_dir_open@Base 0.4.17
189 click_dir_read_name@Base 0.4.17
190@@ -57,6 +63,7 @@
191 click_hook_run_commands@Base 0.4.17
192 click_hook_sync@Base 0.4.17
193 click_hooks_error_quark@Base 0.4.17
194+ click_install_flags_get_type@Base 0.4.34
195 click_installed_package_get_package@Base 0.4.17
196 click_installed_package_get_path@Base 0.4.17
197 click_installed_package_get_type@Base 0.4.17
198
199=== modified file 'lib/click/Makefile.am'
200--- lib/click/Makefile.am 2014-06-30 16:48:31 +0000
201+++ lib/click/Makefile.am 2015-12-09 20:26:30 +0000
202@@ -9,19 +9,12 @@
203 -Wno-unused-function \
204 -Wno-unused-variable
205 VALAC = $(srcdir)/valac-wrapper
206-AM_VALAFLAGS = \
207- -H click.h \
208- --gir Click-0.4.gir \
209- --library click-0.4 \
210- --pkg posix \
211- --pkg gee-0.8 \
212- --pkg json-glib-1.0 \
213- --target-glib 2.32
214
215 lib_LTLIBRARIES = libclick-0.4.la
216
217 libclick_0_4_la_SOURCES = \
218 database.vala \
219+ dbus-interface.vala \
220 deb822.vala \
221 framework.vala \
222 hooks.vala \
223@@ -31,6 +24,15 @@
224 query.vala \
225 user.vala
226
227+libclick_0_4_la_VALAFLAGS = \
228+ -H click.h \
229+ --gir Click-0.4.gir \
230+ --library click-0.4 \
231+ --pkg posix \
232+ --pkg gee-0.8 \
233+ --pkg json-glib-1.0 \
234+ --target-glib 2.32
235+
236 EXTRA_libclick_0_4_la_DEPENDENCIES = \
237 click.sym
238
239@@ -55,11 +57,15 @@
240
241 do_subst = sed \
242 -e 's,[@]sysconfdir[@],$(sysconfdir),g' \
243- -e 's,[@]pkgdatadir[@],$(pkgdatadir),g'
244+ -e 's,[@]pkgdatadir[@],$(pkgdatadir),g' \
245+ -e 's,[@]pkglibexecdir[@],$(pkglibexecdir),g'
246
247 paths.vala: paths.vala.in Makefile
248 $(do_subst) < $(srcdir)/paths.vala.in > $@
249
250+com.ubuntu.Click.service: paths.vala.in Makefile
251+ $(do_subst) < $(srcdir)/com.ubuntu.Click.service.in > $@
252+
253 includeclickdir = $(includedir)/click-0.4
254 includeclick_HEADERS = \
255 $(HEADER_FILES)
256@@ -102,3 +108,27 @@
257
258 %.typelib: %.gir
259 $(INTROSPECTION_COMPILER) $(INTROSPECTION_COMPILER_ARGS) $< -o $@
260+
261+pkglibexec_PROGRAMS = click-dbus-service
262+click_dbus_service_VALAFLAGS = \
263+ --vapidir $(builddir) \
264+ --pkg posix \
265+ --pkg gee-0.8 \
266+ --pkg json-glib-1.0 \
267+ --pkg click-0.4 \
268+ --target-glib 2.32
269+click_dbus_service_LDADD = \
270+ libclick-0.4.la \
271+ $(LIBCLICK_LIBS)
272+click_dbus_service_LDFLAGS = \
273+ $(COVERAGE_LDFLAGS)
274+click_dbus_service_SOURCES = \
275+ dbus-service.vala \
276+ posix-extra.vapi
277+
278+dbussystemdir = $(DBUS_SYS_DIR)
279+dist_dbussystem_DATA = com.ubuntu.Click.conf
280+
281+dbusservicesdir = $(DBUS_SERVICES_DIR)
282+dbusservices_DATA = com.ubuntu.Click.service
283+EXTRA_DIST += com.ubuntu.Click.service.in
284
285=== modified file 'lib/click/click.sym'
286--- lib/click/click.sym 2014-03-31 10:50:20 +0000
287+++ lib/click/click.sym 2015-12-09 20:26:30 +0000
288@@ -16,6 +16,12 @@
289 click_db_maybe_remove
290 click_db_new
291 click_db_read
292+click_dbus_error_quark
293+click_dbus_interface_get_type
294+click_dbus_interface_install_file
295+click_dbus_interface_proxy_get_type
296+click_dbus_interface_register_object
297+click_dbus_interface_remove_package
298 click_dir_get_type
299 click_dir_open
300 click_dir_read_name
301@@ -55,6 +61,7 @@
302 click_hook_run_commands
303 click_hook_sync
304 click_hooks_error_quark
305+click_install_flags_get_type
306 click_installed_package_get_package
307 click_installed_package_get_path
308 click_installed_package_get_type
309
310=== added file 'lib/click/com.ubuntu.Click.conf'
311--- lib/click/com.ubuntu.Click.conf 1970-01-01 00:00:00 +0000
312+++ lib/click/com.ubuntu.Click.conf 2015-12-09 20:26:30 +0000
313@@ -0,0 +1,23 @@
314+<?xml version="1.0" encoding="UTF-8"?>
315+
316+<!DOCTYPE busconfig PUBLIC
317+ "-//freedesktop//DTD D-BUS Bus Configuration 1.0//EN"
318+ "http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd">
319+<busconfig>
320+
321+ <policy user="root">
322+ <allow own="com.ubuntu.Click"/>
323+ </policy>
324+
325+ <policy context="default">
326+ <allow send_destination="com.ubuntu.Click"
327+ send_interface="com.ubuntu.Click"/>
328+ <allow send_destination="com.ubuntu.Click"
329+ send_interface="org.freedesktop.DBus.Introspectable"/>
330+ <allow send_destination="com.ubuntu.Click"
331+ send_interface="org.freedesktop.DBus.Peer"/>
332+ <allow send_destination="com.ubuntu.Click"
333+ send_interface="org.freedesktop.DBus.Properties"/>
334+ </policy>
335+
336+</busconfig>
337
338=== added file 'lib/click/com.ubuntu.Click.service.in'
339--- lib/click/com.ubuntu.Click.service.in 1970-01-01 00:00:00 +0000
340+++ lib/click/com.ubuntu.Click.service.in 2015-12-09 20:26:30 +0000
341@@ -0,0 +1,4 @@
342+[D-BUS Service]
343+Name=com.ubuntu.Click
344+Exec=@pkglibexecdir@/click-dbus-service
345+User=root
346
347=== added file 'lib/click/com.ubuntu.Click.xml'
348--- lib/click/com.ubuntu.Click.xml 1970-01-01 00:00:00 +0000
349+++ lib/click/com.ubuntu.Click.xml 2015-12-09 20:26:30 +0000
350@@ -0,0 +1,21 @@
351+<?xml version="1.0" encoding="UTF-8"?>
352+
353+<!DOCTYPE node PUBLIC
354+ "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN"
355+ "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
356+<node name="/com/ubuntu/Click">
357+ <interface name="com.ubuntu.Click">
358+ <method name="InstallFile">
359+ <arg type="s" name="filename" direction="in"/>
360+ <arg type="u" name="flags" direction="in"/>
361+ <arg type="s" name="package" direction="out"/>
362+ <arg type="s" name="version" direction="out"/>
363+ <arg type="a{sv}" name="details" direction="out"/>
364+ </method>
365+
366+ <method name="RemovePackage">
367+ <arg type="s" name="package" direction="in"/>
368+ <arg type="s" name="version" direction="in"/>
369+ </method>
370+ </interface>
371+</node>
372
373=== added file 'lib/click/dbus-interface.vala'
374--- lib/click/dbus-interface.vala 1970-01-01 00:00:00 +0000
375+++ lib/click/dbus-interface.vala 2015-12-09 20:26:30 +0000
376@@ -0,0 +1,66 @@
377+/* Copyright (C) 2014 Canonical Ltd.
378+ * Author: Colin Watson <cjwatson@ubuntu.com>
379+ *
380+ * This program is free software: you can redistribute it and/or modify
381+ * it under the terms of the GNU General Public License as published by
382+ * the Free Software Foundation; version 3 of the License.
383+ *
384+ * This program is distributed in the hope that it will be useful,
385+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
386+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
387+ * GNU General Public License for more details.
388+ *
389+ * You should have received a copy of the GNU General Public License
390+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
391+ */
392+
393+/* The Click D-Bus interface. */
394+
395+namespace Click {
396+
397+[DBus (name = "com.ubuntu.Click.InstallFlags")]
398+[Flags]
399+public enum InstallFlags {
400+ FORCE_MISSING_FRAMEWORK,
401+ ALLOW_UNAUTHENTICATED
402+}
403+
404+[DBus (name = "com.ubuntu.Click.Error")]
405+public errordomain DBusError {
406+ /**
407+ * Failure to determine the connected user name.
408+ */
409+ AUTHENTICATION,
410+ /**
411+ * Failure to drop privileges.
412+ */
413+ DROP_PRIVS,
414+ /**
415+ * Failure to read manifest.
416+ */
417+ MANIFEST,
418+ /**
419+ * Failure to install package.
420+ */
421+ FAILED_TO_INSTALL,
422+ /**
423+ * Failure to remove package.
424+ */
425+ FAILED_TO_REMOVE
426+}
427+
428+[DBus (name = "com.ubuntu.Click")]
429+public interface DBusInterface : Object {
430+ public abstract void
431+ install_file (string filename, InstallFlags flags,
432+ out string package, out string version,
433+ out HashTable<string, Variant> details,
434+ BusName sender)
435+ throws Error;
436+
437+ public abstract void
438+ remove_package (string package, string version, BusName sender)
439+ throws Error;
440+}
441+
442+}
443
444=== added file 'lib/click/dbus-service.vala'
445--- lib/click/dbus-service.vala 1970-01-01 00:00:00 +0000
446+++ lib/click/dbus-service.vala 2015-12-09 20:26:30 +0000
447@@ -0,0 +1,297 @@
448+/* Copyright (C) 2014 Canonical Ltd.
449+ * Author: Colin Watson <cjwatson@ubuntu.com>
450+ *
451+ * This program is free software: you can redistribute it and/or modify
452+ * it under the terms of the GNU General Public License as published by
453+ * the Free Software Foundation; version 3 of the License.
454+ *
455+ * This program is distributed in the hope that it will be useful,
456+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
457+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
458+ * GNU General Public License for more details.
459+ *
460+ * You should have received a copy of the GNU General Public License
461+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
462+ */
463+
464+/* The Click D-Bus service. */
465+
466+namespace Click {
467+
468+[DBus (name = "com.ubuntu.Click")]
469+public class DBusService : Object, DBusInterface {
470+ private DBusConnection conn;
471+ private DBusProxy proxy_uid;
472+
473+ public DBusService (DBusConnection conn) throws Error
474+ {
475+ this.conn = conn;
476+ proxy_uid = new DBusProxy.sync
477+ (conn,
478+ DBusProxyFlags.DO_NOT_LOAD_PROPERTIES |
479+ DBusProxyFlags.DO_NOT_CONNECT_SIGNALS,
480+ null,
481+ "org.freedesktop.DBus",
482+ "/org/freedesktop/DBus",
483+ "org.freedesktop.DBus");
484+ }
485+
486+ private string
487+ get_connected_username (BusName sender) throws Error
488+ {
489+ var uid_reply = proxy_uid.call_sync
490+ ("GetConnectionUnixUser", new Variant ("(s)", sender),
491+ DBusCallFlags.NONE, -1);
492+ uint uid;
493+ uid_reply.get ("(u)", out uid);
494+ errno = 0;
495+ unowned Posix.Passwd pw = Posix.getpwuid (uid);
496+ if (pw == null)
497+ throw new DBusError.AUTHENTICATION
498+ ("Cannot get password file entry for UID " +
499+ "%d: %s", uid, strerror (errno));
500+ return pw.pw_name;
501+ }
502+
503+ private void
504+ priv_drop_failure (string name) throws DBusError
505+ {
506+ throw new DBusError.DROP_PRIVS
507+ ("Cannot drop privileges (%s): %s",
508+ name, strerror (errno));
509+ }
510+
511+ private void
512+ drop_privileges (string username) throws Error
513+ {
514+ if (Posix.geteuid () != 0)
515+ return;
516+ unowned Posix.Passwd pw = Posix.getpwnam (username);
517+ if (pw == null)
518+ throw new DBusError.DROP_PRIVS
519+ ("Cannot get password file entry for user " +
520+ "'%s': %s", username, strerror (errno));
521+ Posix.gid_t[] supp = {};
522+ Posix.setgrent ();
523+ unowned PosixExtra.Group? gr;
524+ while ((gr = PosixExtra.getgrent ()) != null) {
525+ foreach (unowned string member in gr.gr_mem) {
526+ if (member == username) {
527+ supp += gr.gr_gid;
528+ break;
529+ }
530+ }
531+ }
532+ Posix.endgrent ();
533+ if (PosixExtra.setgroups (supp.length, supp) < 0)
534+ priv_drop_failure ("setgroups");
535+ /* Portability note: this assumes that we have
536+ * [gs]etres[gu]id, which is true on Linux but not
537+ * necessarily elsewhere. If you need to support something
538+ * else, there are reasonably standard alternatives
539+ * involving other similar calls; see e.g.
540+ * gnulib/lib/idpriv-drop.c.
541+ */
542+ if (PosixExtra.setresgid (pw.pw_gid, pw.pw_gid, pw.pw_gid) < 0)
543+ priv_drop_failure ("setresgid");
544+ if (PosixExtra.setresuid (pw.pw_uid, pw.pw_uid, pw.pw_uid) < 0)
545+ priv_drop_failure ("setresuid");
546+ {
547+ Posix.uid_t ruid, euid, suid;
548+ Posix.gid_t rgid, egid, sgid;
549+ assert (PosixExtra.getresuid (out ruid, out euid,
550+ out suid) == 0 &&
551+ ruid == pw.pw_uid && euid == pw.pw_uid &&
552+ suid == pw.pw_uid);
553+ assert (PosixExtra.getresgid (out rgid, out egid,
554+ out sgid) == 0 &&
555+ rgid == pw.pw_gid && egid == pw.pw_gid &&
556+ sgid == pw.pw_gid);
557+ }
558+ Posix.umask (get_umask () | Posix.S_IWOTH);
559+ }
560+
561+ private bool
562+ euid_access (string username, string path, int mode) throws Error
563+ {
564+ var pid = Posix.fork ();
565+ if (pid < 0)
566+ throw new DBusError.DROP_PRIVS
567+ ("Cannot fork: %s", strerror (errno));
568+ else if (pid == 0) { /* child */
569+ drop_privileges (username);
570+ Posix._exit (Posix.access (path, mode) == 0 ? 0 : 1);
571+ throw new DBusError.DROP_PRIVS ("Unreachable");
572+ } else { /* parent */
573+ int status;
574+ if (Posix.waitpid (pid, out status, 0) < 0)
575+ throw new DBusError.DROP_PRIVS
576+ ("Cannot wait for privilege-dropped " +
577+ "subprocess: %s", strerror (errno));
578+ return status == 0;
579+ }
580+ }
581+
582+ private Json.Object
583+ get_manifest (string filename) throws Error
584+ {
585+ string[] command = {"click", "info", filename};
586+ string manifest_text;
587+ string click_stderr;
588+ int click_status;
589+ Process.spawn_sync
590+ (null, command, null, SpawnFlags.SEARCH_PATH, null,
591+ out manifest_text, out click_stderr,
592+ out click_status);
593+ try {
594+ Process.check_exit_status (click_status);
595+ } catch (Error e) {
596+ throw new DBusError.MANIFEST
597+ ("\"click info %s\" failed.\n%s",
598+ filename, click_stderr);
599+ }
600+
601+ var parser = new Json.Parser ();
602+ parser.load_from_data (manifest_text);
603+ return parser.get_root ().get_object ();
604+ }
605+
606+ private string?
607+ get_field_string (Json.Object manifest, string field)
608+ {
609+ var node = manifest.get_member (field);
610+ return node != null ? node.dup_string () : null;
611+ }
612+
613+ private Json.Object?
614+ get_field_object (Json.Object manifest, string field)
615+ {
616+ var node = manifest.get_member (field);
617+ return node != null ? node.dup_object () : null;
618+ }
619+
620+ private bool
621+ get_field_boolean (Json.Object manifest, string field, bool def)
622+ {
623+ var node = manifest.get_member (field);
624+ return node != null ? node.get_boolean () : def;
625+ }
626+
627+ private void
628+ installed_manifest (Json.Object manifest, string username,
629+ out string package, out string version,
630+ ref HashTable<string, Variant> details)
631+ {
632+ package = get_field_string (manifest, "name");
633+ version = get_field_string (manifest, "version");
634+ if (package == null || version == null)
635+ return;
636+ var architecture = get_field_string (manifest, "architecture");
637+ if (architecture != null)
638+ details["architecture"] = architecture;
639+ /* A missing "_removable" entry in the manifest means that
640+ * we just installed the package, so it must be removable.
641+ */
642+ details["removable"] = get_field_boolean
643+ (manifest, "_removable", true);
644+ string[] app_names = {};
645+ var hooks = get_field_object (manifest, "hooks");
646+ if (hooks != null) {
647+ foreach (var app_name in hooks.get_members ())
648+ app_names += app_name;
649+ details["app_names"] = app_names;
650+ }
651+ }
652+
653+ public void
654+ install_file (string filename, InstallFlags flags,
655+ out string package, out string version,
656+ out HashTable<string, Variant> details,
657+ BusName sender)
658+ throws Error
659+ {
660+ var username = get_connected_username (sender);
661+ message (@"Click: installing $filename for $username");
662+ if (! euid_access (username, filename, Posix.R_OK))
663+ throw new DBusError.FAILED_TO_INSTALL
664+ ("User %s cannot read %s", username, filename);
665+ string[] command = {"click", "install", @"--user=$username"};
666+ if (InstallFlags.FORCE_MISSING_FRAMEWORK in flags)
667+ command += "--force-missing-framework";
668+ if (InstallFlags.ALLOW_UNAUTHENTICATED in flags)
669+ command += "--allow-unauthenticated";
670+ command += filename;
671+ string click_stderr;
672+ int click_status;
673+ Process.spawn_sync
674+ (null, command, null,
675+ SpawnFlags.SEARCH_PATH |
676+ SpawnFlags.STDOUT_TO_DEV_NULL,
677+ null, null, out click_stderr, out click_status);
678+ try {
679+ Process.check_exit_status (click_status);
680+ } catch (Error e) {
681+ throw new DBusError.FAILED_TO_INSTALL
682+ ("%s failed to install.\n%s",
683+ filename, click_stderr);
684+ }
685+ package = "";
686+ version = "";
687+ details = new HashTable<string, Variant> (str_hash, str_equal);
688+ try {
689+ installed_manifest
690+ (get_manifest (filename), username,
691+ out package, out version, ref details);
692+ } catch (Error e) {
693+ stderr.printf ("Failed to get installed package " +
694+ "manifest: %s", e.message);
695+ }
696+ }
697+
698+ public void
699+ remove_package (string package, string version, BusName sender)
700+ throws Error
701+ {
702+ var username = get_connected_username (sender);
703+ message (@"Click: removing $package $version for $username");
704+ var db = new Click.DB ();
705+ db.read ();
706+ var registry = new Click.User.for_user (db, username);
707+ var old_version = registry.get_version (package);
708+ if (old_version != version) {
709+ throw new DBusError.FAILED_TO_REMOVE
710+ ("Not removing Click package %s %s; " +
711+ "does not match current version %s.",
712+ package, version, old_version);
713+ }
714+ registry.remove (package);
715+ db.maybe_remove (package, version);
716+ /* TODO: remove data? */
717+ }
718+
719+ private static void
720+ on_bus_acquired (DBusConnection conn)
721+ {
722+ try {
723+ conn.register_object
724+ ("/com/ubuntu/Click", new DBusService (conn));
725+ } catch (Error e) {
726+ stderr.printf ("Could not register service: %s\n",
727+ e.message);
728+ Process.exit (Posix.EXIT_FAILURE);
729+ }
730+ }
731+
732+ static void
733+ main ()
734+ {
735+ Environment.set_variable ("CLICK_IN_DBUS_SERVICE", "1", true);
736+ Bus.own_name
737+ (BusType.SYSTEM, "com.ubuntu.Click",
738+ BusNameOwnerFlags.NONE, on_bus_acquired, () => {},
739+ () => stderr.printf ("Could not acquire name\n"));
740+ new MainLoop ().run ();
741+ }
742+}
743+
744+}
745
746=== modified file 'lib/click/valac-wrapper.in'
747--- lib/click/valac-wrapper.in 2014-03-06 07:03:09 +0000
748+++ lib/click/valac-wrapper.in 2015-12-09 20:26:30 +0000
749@@ -22,12 +22,13 @@
750
751 # Keep this in sync with any options used in lib/click/Makefile.am. -C is
752 # emitted by automake.
753-eval set -- "$(getopt -o CH: -l gir:,library:,pkg:,target-glib: -- "$@")" || \
754+eval set -- "$(getopt -o CH: -l vapidir:,gir:,library:,pkg:,target-glib: -- "$@")" || \
755 { echo "$0: failed to parse valac options" >&2; exit 2; }
756 while :; do
757 case $1 in
758 -C) shift ;;
759 -H) header="$2"; shift 2 ;;
760+ --vapidir) shift 2 ;;
761 --pkg|--target-glib) shift 2 ;;
762 --gir) gir="$2"; shift 2 ;;
763 --library) library="$2"; shift 2 ;;
764@@ -36,10 +37,13 @@
765 esac
766 done
767
768+if [ -z "$library" ]; then
769+ # We're building something else, not a library.
770+ exit 0
771+fi
772+
773 [ "$header" ] || { echo "$0: failed to find -H in valac options" >&2; exit 2; }
774 [ "$gir" ] || { echo "$0: failed to find --gir in valac options" >&2; exit 2; }
775-[ "$library" ] || \
776- { echo "$0: failed to find --library in valac options" >&2; exit 2; }
777
778 if egrep 'Gee|gee_' "$header"; then
779 echo "libgee should not be exposed in our public header file." >&2

Subscribers

People subscribed via source and target branches

to all changes: