Example #1
0
    def install(self, pkgplan, orig):
        """Client-side method that installs a link."""

        path = self.attrs["path"]
        target = self.attrs["target"]

        path = os.path.normpath(
            os.path.sep.join((pkgplan.image.get_root(), path)))

        if not os.path.exists(os.path.dirname(path)):
            self.makedirs(os.path.dirname(path), mode=0755)

        # XXX The exists-unlink-symlink path appears to be as safe as it
        # gets to modify a link with the current symlink(2) interface.
        if os.path.lexists(path):
            try:
                os.unlink(path)
            except EnvironmentError, e:
                if e.errno == errno.EPERM:
                    # Unlinking a directory gives EPERM,
                    # which is confusing, so ignore errno
                    # and give a good message.
                    path = self.attrs["path"]
                    raise ActionExecutionError(
                        self,
                        e,
                        "attempted to remove link '%s' but "
                        "found a directory" % path,
                        ignoreerrno=True)
                else:
                    raise ActionExecutionError(self, e)
Example #2
0
        def install(self, pkgplan, orig):
                """Client-side method that installs a hard link."""

                target = self.get_target_path()
                path = self.get_installed_path(pkgplan.image.get_root())

                # Don't allow installation through symlinks.
                self.fsobj_checkpath(pkgplan, path)

                if not os.path.exists(os.path.dirname(path)):
                        self.makedirs(os.path.dirname(path),
                            mode=misc.PKG_DIR_MODE,
                            fmri=pkgplan.destination_fmri)
                elif os.path.exists(path):
                        self.remove(pkgplan)

                fulltarget = os.path.normpath(os.path.sep.join(
                    (pkgplan.image.get_root(), target)))

                try:
                        os.link(fulltarget, path)
                except EnvironmentError as e:
                        if e.errno != errno.ENOENT:
                                raise ActionExecutionError(self, error=e)

                        # User or another process has removed target for
                        # hardlink, a package hasn't declared correct
                        # dependencies, or the target hasn't been installed
                        # yet.
                        err_txt = _("Unable to create hard link {path}; "
                            "target {target} is missing.").format(
                            path=path, target=fulltarget)
                        raise ActionExecutionError(self, details=err_txt,
                            error=e, fmri=pkgplan.destination_fmri)
Example #3
0
        def install(self, pkgplan, orig):
                """Client-side method that installs a hard link."""

                path = self.attrs["path"]
                target = self.get_target_path()

                path = os.path.normpath(os.path.sep.join(
                    (pkgplan.image.get_root(), path)))

                if not os.path.exists(os.path.dirname(path)):
                        self.makedirs(os.path.dirname(path), mode=0755)
                elif os.path.exists(path):
                        os.unlink(path)

                fulltarget = os.path.normpath(os.path.sep.join(
                    (pkgplan.image.get_root(), target)))

                try:
                        os.link(fulltarget, path)
                except EnvironmentError, e:
                        if e.errno == errno.ENOENT:
                                raise ActionExecutionError(self, e,
                                    "missing hard link target '%s'" % target)
                        else:
                                raise ActionExecutionError(self, e)
Example #4
0
    def install(self, pkgplan, orig):
        """Client-side method that installs the license."""
        owner = 0
        group = 0

        # ensure "path" is initialized.  it may not be if we've loaded
        # a plan that was previously prepared.
        self.preinstall(pkgplan, orig)

        stream = self.data()

        path = self.get_installed_path(pkgplan.image.get_root())

        # make sure the directory exists and the file is writable
        if not os.path.exists(os.path.dirname(path)):
            self.makedirs(os.path.dirname(path),
                          mode=misc.PKG_DIR_MODE,
                          fmri=pkgplan.destination_fmri)
        elif os.path.exists(path):
            os.chmod(path, misc.PKG_FILE_MODE)

        lfile = open(path, "wb")
        try:
            hash_attr, hash_val, hash_func = \
                digest.get_preferred_hash(self)
            shasum = misc.gunzip_from_stream(stream,
                                             lfile,
                                             hash_func=hash_func)
        except zlib.error as e:
            raise ActionExecutionError(
                self,
                details=_("Error "
                          "decompressing payload: {0}").format(" ".join(
                              [str(a) for a in e.args])),
                error=e)
        finally:
            lfile.close()
            stream.close()

        if shasum != hash_val:
            raise ActionExecutionError(
                self,
                details=_("Action "
                          "data hash verification failure: expected: "
                          "{expected} computed: {actual} action: "
                          "{action}").format(expected=hash_val,
                                             actual=shasum,
                                             action=self))

        os.chmod(path, misc.PKG_RO_FILE_MODE)

        try:
            portable.chown(path, owner, group)
        except OSError as e:
            if e.errno != errno.EPERM:
                raise
Example #5
0
    def install(self, pkgplan, orig):
        """Client-side method that installs a file."""

        mode = None
        try:
            mode = int(self.attrs.get("mode", None), 8)
        except (TypeError, ValueError):
            # Mode isn't valid, so let validate raise a more
            # informative error.
            self.validate(fmri=pkgplan.destination_fmri)

        owner, group = self.get_fsobj_uid_gid(pkgplan,
                                              pkgplan.destination_fmri)

        final_path = self.get_installed_path(pkgplan.image.get_root())

        # Don't allow installation through symlinks.
        self.fsobj_checkpath(pkgplan, final_path)

        if not os.path.exists(os.path.dirname(final_path)):
            self.makedirs(os.path.dirname(final_path),
                          mode=misc.PKG_DIR_MODE,
                          fmri=pkgplan.destination_fmri)
        elif (not orig and not pkgplan.origin_fmri and "preserve" in self.attrs
              and self.attrs["preserve"] not in ("abandon", "install-only")
              and os.path.isfile(final_path)):
            # Unpackaged editable file is already present during
            # initial install; salvage it before continuing.
            pkgplan.salvage(final_path)

        # XXX If we're upgrading, do we need to preserve file perms from
        # existing file?

        # check if we have a save_file active; if so, simulate file
        # being already present rather than installed from scratch

        if "save_file" in self.attrs:
            orig = self.restore_file(pkgplan.image)

        # See if we need to preserve the file, and if so, set that up.
        #
        # XXX What happens when we transition from preserve to
        # non-preserve or vice versa? Do we want to treat a preserve
        # attribute as turning the action into a critical action?
        #
        # XXX We should save the originally installed file.  It can be
        # used as an ancestor for a three-way merge, for example.  Where
        # should it be stored?
        pres_type = self._check_preserve(orig, pkgplan)
        do_content = True
        old_path = None
        if pres_type == True or (pres_type and pkgplan.origin_fmri
                                 == pkgplan.destination_fmri):
            # File is marked to be preserved and exists so don't
            # reinstall content.
            do_content = False
        elif pres_type == "legacy":
            # Only rename old file if this is a transition to
            # preserve=legacy from something else.
            if orig.attrs.get("preserve", None) != "legacy":
                old_path = final_path + ".legacy"
        elif pres_type == "renameold.update":
            old_path = final_path + ".update"
        elif pres_type == "renameold":
            old_path = final_path + ".old"
        elif pres_type == "renamenew":
            final_path = final_path + ".new"
        elif pres_type == "abandon":
            return

        # If it is a directory (and not empty) then we should
        # salvage the contents.
        if os.path.exists(final_path) and \
            not os.path.islink(final_path) and \
            os.path.isdir(final_path):
            try:
                os.rmdir(final_path)
            except OSError as e:
                if e.errno == errno.ENOENT:
                    pass
                elif e.errno in (errno.EEXIST, errno.ENOTEMPTY):
                    pkgplan.salvage(final_path)
                elif e.errno != errno.EACCES:
                    # this happens on Windows
                    raise

        # XXX This needs to be modularized.
        if do_content and self.needsdata(orig, pkgplan):
            tfilefd, temp = tempfile.mkstemp(dir=os.path.dirname(final_path))
            if not self.data:
                # The state of the filesystem changed after the
                # plan was prepared; attempt a one-off
                # retrieval of the data.
                self.data = self.__set_data(pkgplan)
            stream = self.data()
            tfile = os.fdopen(tfilefd, "wb")
            try:
                # Always verify using the most preferred hash
                hash_attr, hash_val, hash_func  = \
                    digest.get_preferred_hash(self)
                shasum = misc.gunzip_from_stream(stream, tfile, hash_func)
            except zlib.error as e:
                raise ActionExecutionError(
                    self,
                    details=_("Error decompressing payload: "
                              "{0}").format(" ".join([str(a)
                                                      for a in e.args])),
                    error=e)
            finally:
                tfile.close()
                stream.close()

            if shasum != hash_val:
                raise ActionExecutionError(
                    self,
                    details=_("Action data hash verification "
                              "failure: expected: {expected} computed: "
                              "{actual} action: {action}").format(
                                  expected=hash_val,
                                  actual=shasum,
                                  action=self))

        else:
            temp = final_path

        try:
            os.chmod(temp, mode)
        except OSError as e:
            # If the file didn't exist, assume that's intentional,
            # and drive on.
            if e.errno != errno.ENOENT:
                raise
            else:
                return

        try:
            portable.chown(temp, owner, group)
        except OSError as e:
            if e.errno != errno.EPERM:
                raise

        # XXX There's a window where final_path doesn't exist, but we
        # probably don't care.
        if do_content and old_path:
            try:
                portable.rename(final_path, old_path)
            except OSError as e:
                if e.errno != errno.ENOENT:
                    # Only care if file isn't gone already.
                    raise

        # This is safe even if temp == final_path.
        try:
            portable.rename(temp, final_path)
        except OSError as e:
            raise api_errors.FileInUseException(final_path)

        # Handle timestamp if specified (and content was installed).
        if do_content and "timestamp" in self.attrs:
            t = misc.timestamp_to_time(self.attrs["timestamp"])
            try:
                os.utime(final_path, (t, t))
            except OSError as e:
                if e.errno != errno.EACCES:
                    raise

                # On Windows, the time cannot be changed on a
                # read-only file
                os.chmod(final_path, stat.S_IRUSR | stat.S_IWUSR)
                os.utime(final_path, (t, t))
                os.chmod(final_path, mode)

        # Handle system attributes.
        sattr = self.attrs.get("sysattr")
        if sattr:
            if isinstance(sattr, list):
                sattr = ",".join(sattr)
            sattrs = sattr.split(",")
            if len(sattrs) == 1 and \
                sattrs[0] not in portable.get_sysattr_dict():
                # not a verbose attr, try as a compact attr seq
                arg = sattrs[0]
            else:
                arg = sattrs

            try:
                portable.fsetattr(final_path, arg)
            except OSError as e:
                if e.errno != errno.EINVAL:
                    raise
                warn = _("System attributes are not supported "
                         "on the target image filesystem; 'sysattr'"
                         " ignored for {0}").format(self.attrs["path"])
                pkgplan.image.imageplan.pd.add_item_message(
                    pkgplan.destination_fmri,
                    misc.time_to_timestamp(time.time()), MSG_WARNING, warn)
            except ValueError as e:
                warn = _("Could not set system attributes for {path}"
                         "'{attrlist}': {err}").format(attrlist=sattr,
                                                       err=e,
                                                       path=self.attrs["path"])
                pkgplan.image.imageplan.pd.add_item_message(
                    pkgplan.destination_fmri,
                    misc.time_to_timestamp(time.time()), MSG_WARNING, warn)