--- a/src/modules/actions/file.py Sun Sep 30 18:34:43 2007 -0700
+++ b/src/modules/actions/file.py Mon Oct 01 16:59:51 2007 -0700
@@ -34,6 +34,7 @@
import grp
import pwd
import errno
+import sha
import generic
@@ -63,10 +64,32 @@
omode = int(orig.attrs["mode"], 8)
oowner = pwd.getpwnam(orig.attrs["owner"]).pw_uid
ogroup = grp.getgrnam(orig.attrs["group"]).gr_gid
+ ohash = orig.hash
- # If we're not upgrading, or the file contents have changed,
- # retrieve the file and write it to a temporary location.
- # For ELF files, only write the new file if the elfhash changed.
+ # If the action has been marked with a preserve attribute, and
+ # the file exists and has a contents hash different from what
+ # the system expected it to be, then we preserve the original
+ # file in some way, depending on the value of preserve.
+ #
+ # 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?
+ if "preserve" in self.attrs and os.path.isfile(final_path):
+ cfile = file(final_path)
+ chash = sha.sha(cfile.read()).hexdigest()
+
+ # 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?
+ if chash != ohash:
+ pres_type = self.attrs["preserve"]
+ if pres_type == "renameold":
+ old_path = final_path + ".old"
+ elif pres_type == "renamenew":
+ final_path = final_path + ".new"
+ else:
+ return
+
# XXX This needs to be modularized.
# XXX This needs to be controlled by policy.
if self.needsdata(orig):
@@ -93,9 +116,17 @@
if e.errno != errno.EPERM:
raise
+ # XXX There's a window where final_path doesn't exist, but we
+ # probably don't care.
+ if "old_path" in locals():
+ os.rename(final_path, old_path)
+
# This is safe even if temp == final_path.
os.rename(temp, final_path)
+ # If we're not upgrading, or the file contents have changed,
+ # retrieve the file and write it to a temporary location.
+ # For ELF files, only write the new file if the elfhash changed.
def needsdata(self, orig):
bothelf = orig and "elfhash" in orig.attrs and "elfhash" in self.attrs
if not orig or \
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/tests/preserve.ksh Mon Oct 01 16:59:51 2007 -0700
@@ -0,0 +1,55 @@
+#!/bin/ksh -px
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+
+# Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+
+eval `pkgsend open test/preserve/[email protected]`
+if [ $? != 0 ]; then
+ echo \*\* script aborted: couldn\'t open test/preserve/A
+ exit 1
+fi
+
+echo "This is the old version" > /tmp/test1
+
+echo $PKG_TRANS_ID
+pkgsend add dir 0755 root sys /bin
+pkgsend add file 0644 root sys /bin/test1 /tmp/test1 preserve=renamenew
+pkgsend add file 0644 root sys /bin/test2 /tmp/test1 preserve=renameold
+pkgsend add file 0644 root sys /bin/test3 /tmp/test1 preserve=true
+pkgsend close
+
+eval `pkgsend open test/preserve/[email protected]`
+if [ $? != 0 ]; then
+ echo \*\* script aborted: couldn\'t open test/preserve/A
+ exit 1
+fi
+
+echo "This is the new version" > /tmp/test1
+
+echo $PKG_TRANS_ID
+pkgsend add dir 0755 root sys /bin
+pkgsend add file 0644 root sys /bin/test1 /tmp/test1 preserve=renamenew
+pkgsend add file 0644 root sys /bin/test2 /tmp/test1 preserve=renameold
+pkgsend add file 0644 root sys /bin/test3 /tmp/test1 preserve=true
+pkgsend close
+
+rm /tmp/test1
--- a/src/util/distro-import/Makefile Sun Sep 30 18:34:43 2007 -0700
+++ b/src/util/distro-import/Makefile Mon Oct 01 16:59:51 2007 -0700
@@ -30,7 +30,7 @@
TMPPKGS=SUNWcsdreplace
-default: $(TMPPKGS)
+default: $(TMPPKGS) cluster.import
cluster.import: $(WOS_PATH)/.clustertoc
./clustertoc2import.py $(WOS_PATH)/.clustertoc | egrep -v 'SUNWjds-registration|SUNWdttsr|SUNWdttsu' > $@
@@ -53,5 +53,5 @@
pkgmk -r `pwd` -f [email protected] -d `pwd` -o
-import: cluster.import
+import: cluster.import $(TMPPKGS)
./solaris.py -w $(WOS_PATH) all.i386
--- a/src/util/distro-import/solaris.py Sun Sep 30 18:34:43 2007 -0700
+++ b/src/util/distro-import/solaris.py Mon Oct 01 16:59:51 2007 -0700
@@ -253,6 +253,25 @@
for k, g in groupby((f for f in pkg.files if f.type in "fev"), fn):
groups.append(list(g))
+ def otherattrs(action):
+ s = " ".join(
+ "%s=%s" % (a, action.attrs[a])
+ for a in action.attrs
+ if a not in ("owner", "group", "mode", "path")
+ )
+ if s:
+ return " " + s
+ else:
+ return ""
+
+ # Maps class names to preserve attribute values.
+ preserve_dict = {
+ "renameold": "renameold",
+ "renamenew": "renamenew",
+ "preserve": "true",
+ "svmpreserve": "true"
+ }
+
undeps = set()
for g in groups:
pkgname = usedlist[g[0].pathname][0]
@@ -265,13 +284,16 @@
f.attrs["owner"] = pathdict[path].owner
f.attrs["group"] = pathdict[path].group
f.attrs["mode"] = pathdict[path].mode
+ if pathdict[path].klass in preserve_dict.keys():
+ f.attrs["preserve"] = \
+ preserve_dict[pathdict[path].klass]
if hasattr(pathdict[path], "changed_attrs"):
f.attrs.update(
pathdict[path].changed_attrs)
- print " %s add file %s %s %s %s" % \
+ print " %s add file %s %s %s %s%s" % \
(pkg.name, f.attrs["mode"],
f.attrs["owner"], f.attrs["group"],
- path)
+ path, otherattrs(f))
# Write the file to a temporary location.
d = f.data().read()
fd, tmp = mkstemp(prefix="pkg.")