Example #1
0
    def install(*package_names) -> None:

        upgrade()

        cache = Cache()
        cache.update()
        cache.open()

        for name in package_names:

            if name not in cache:
                logger.error('Package %s not found!' % (name, ))
                continue

            package = cache[name]

            if package.is_installed:
                logger.warning('Package %s already installed!' % (name, ))
                continue

            package.mark_install()

        cache.commit(TextFetchProgress(), InstallProgress())

        cache.close()
Example #2
0
    def remove(*package_names) -> None:

        upgrade()

        cache = Cache()
        cache.update()
        cache.open()

        for name in package_names:

            if name not in cache:
                print('Package %s not found!' % (name, ))
                continue

            package = cache[name]

            if not package.is_installed:
                print('Package %s is not installed!' % (name, ))
                continue

            package.mark_delete(purge=True)

        cache.commit(TextFetchProgress(), InstallProgress())

        cache.close()
Example #3
0
    def upgrade() -> None:

        cache = Cache()
        cache.update()
        cache.open()
        cache.update()
        cache.open()
        cache.upgrade(dist_upgrade=True)
        cache.fix_broken()
        cache.commit(TextFetchProgress(), InstallProgress())
        cache.close()
Example #4
0
class Transition(dbus.service.Object):
    def __init__(self, conn=None, object_path=None, bus_name=None):
        super().__init__(conn, object_path, bus_name)

        self.dbus_info = None
        self.polkit = None
        self.enforce_polkit = True
        self.cache = Cache()
        self.lock = None
        self.apt_lock = None
    
    @dbus.service.method(
        'org.pop_os.transition_system.Interface', 
        in_signature='', out_signature='b',
        sender_keyword='sender', connection_keyword='conn'
    )
    def obtain_lock(self, sender=None, conn=None):
        """ Lock the package system. """
        self._check_polkit_privilege(
            sender, conn, 'org.pop_os.transition_system.removedebs'
        )
        print('Obtaining Package manager lock')
        try:
            self.lock = apt_pkg.get_lock('/var/lib/dpkg/lock-frontend', True)
            self.apt_lock = apt_pkg.get_lock('/var/lib/apt/lists/lock', True)
            print('Lock obtained')
            return True
        except apt_pkg.Error:
            print('Could not obtain lock')
            self.lock = None
            self.apt_lock = None
            return False
    
    @dbus.service.method(
        'org.pop_os.transition_system.Interface', 
        in_signature='', out_signature='b',
        sender_keyword='sender', connection_keyword='conn'
    )
    def release_lock(self, sender=None, conn=None):
        """ Unlock the package system. """
        self._check_polkit_privilege(
            sender, conn, 'org.pop_os.transition_system.removedebs'
        )
        print('Releasing package manager lock')
        try:
            os.close(self.lock)
            os.close(self.apt_lock)
            self.lock = None
            self.apt_lock = None
            print('Lock released')
            return True
        except:
            print('Could not release lock')
            return False
    
    @dbus.service.method(
        'org.pop_os.transition_system.Interface', 
        in_signature='', out_signature='b',
        sender_keyword='sender', connection_keyword='conn'
    )
    def open_cache(self, sender=None, conn=None):
        """ Open the package cache. """
        self._check_polkit_privilege(
            sender, conn, 'org.pop_os.transition_system.removedebs'
        )
        if self.lock and self.apt_lock:
            print('Opening package cache')
            self.cache.update()
            self.cache.open()
            print('Cache open')
            return True
        print('No lock, cannot open cache')
        return False
    
    @dbus.service.method(
        'org.pop_os.transition_system.Interface', 
        in_signature='', out_signature='b',
        sender_keyword='sender', connection_keyword='conn'
    )
    def commit_changes(self, sender=None, conn=None):
        """ Commit changes to the cache. """
        self._check_polkit_privilege(
            sender, conn, 'org.pop_os.transition_system.removedebs'
        )
        if self.lock and self.apt_lock:
            self.cache.commit()
            print('Committed changes to cache')
            return True
        print('No lock, Cannot commit changes')
        return False
    
    @dbus.service.method(
        'org.pop_os.transition_system.Interface', 
        in_signature='', out_signature='b',
        sender_keyword='sender', connection_keyword='conn'
    )
    def close_cache(self, sender=None, conn=None):
        """ Close the package cache. """
        self._check_polkit_privilege(
            sender, conn, 'org.pop_os.transition_system.removedebs'
        )
        if self.lock and self.apt_lock:
            self.cache.close()
            print('Package cache closed')
            return True
        print('No lock, cannot close cache')
        return False

    @dbus.service.method(
        'org.pop_os.transition_system.Interface', 
        in_signature='s', out_signature='s',
        sender_keyword='sender', connection_keyword='conn'
    )
    def remove_package(self, package, sender=None, conn=None):
        """ Mark a package for removal."""
        self._check_polkit_privilege(
            sender, conn, 'org.pop_os.transition_system.removedebs'
        )
        if self.lock and self.apt_lock:
            print(f'Marking {package} for removal')
            try:
                pkg = self.cache[package]
                pkg.mark_delete()
                return pkg.name
            except:
                print(f'Could not mark {package} for removal')
                return ''
        print('No lock, cannot mark packages')
        return ''

    @dbus.service.method(
        'org.pop_os.transition_system.Interface', 
        in_signature='', out_signature='',
        sender_keyword='sender', connection_keyword='conn'
    )
    def exit(self, sender=None, conn=None):
        if self.lock and self.apt_lock:
            self.close_cache()
            self.release_lock()
        mainloop.quit()

    def _check_polkit_privilege(self, sender, conn, privilege):
        '''Verify that sender has a given PolicyKit privilege.
        sender is the sender's (private) D-BUS name, such as ":1:42"
        (sender_keyword in @dbus.service.methods). conn is
        the dbus.Connection object (connection_keyword in
        @dbus.service.methods). privilege is the PolicyKit privilege string.
        This method returns if the caller is privileged, and otherwise throws a
        PermissionDeniedByPolicy exception.
        '''

        if sender is None and conn is None:
            # Called locally, not through D-Bus
            return
        
        if not self.enforce_polkit:
            # For testing
            return
        
        if self.dbus_info is None:
            self.dbus_info = dbus.Interface(conn.get_object('org.freedesktop.DBus',
                '/org/freedesktop/DBus/Bus', False), 'org.freedesktop.DBus')
        pid = self.dbus_info.GetConnectionUnixProcessID(sender)
        
        if self.polkit is None:
            self.polkit = dbus.Interface(dbus.SystemBus().get_object(
                'org.freedesktop.PolicyKit1',
                '/org/freedesktop/PolicyKit1/Authority', False),
                'org.freedesktop.PolicyKit1.Authority'
            )
        
        try:
            (is_auth, _, details) = self.polkit.CheckAuthorization(
                ('unix-process', {'pid': dbus.UInt32(pid, variant_level=1),
                'start-time': dbus.UInt64(0, variant_level=1)}), 
                privilege, {'': ''}, dbus.UInt32(1), '', timeout=600
            )

        except dbus.DBusException as e:
            if e._dbus_error_name == 'org.freedesktop.DBus.Error.ServiceUnknown':
                # polkitd timed out, connect again
                self.polkit = None
                return self._check_polkit_privilege(sender, conn, privilege)
            else:
                raise
        
        if not is_auth:
            raise PermissionDeniedByPolicy(privilege)