userland.py revision 99
45N/A#!/usr/bin/python
45N/A#
45N/A# CDDL HEADER START
45N/A#
45N/A# The contents of this file are subject to the terms of the
45N/A# Common Development and Distribution License (the "License").
45N/A# You may not use this file except in compliance with the License.
45N/A#
45N/A# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
45N/A# or http://www.opensolaris.org/os/licensing.
45N/A# See the License for the specific language governing permissions
45N/A# and limitations under the License.
45N/A#
45N/A# When distributing Covered Code, include this CDDL HEADER in each
45N/A# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
45N/A# If applicable, add the following below this CDDL HEADER, with the
45N/A# fields enclosed by brackets "[]" replaced with your own identifying
45N/A# information: Portions Copyright [yyyy] [name of copyright owner]
45N/A#
45N/A# CDDL HEADER END
45N/A#
45N/A
45N/A#
1531N/A# Copyright (c) 2010, 2011, Oracle and/or its affiliates. All rights reserved.
45N/A#
45N/A
45N/A# Some userland consolidation specific lint checks
45N/A
45N/Aimport pkg.lint.base as base
186N/Aimport pkg.elf as elf
84N/Aimport re
45N/Aimport os.path
45N/A
45N/A
45N/Aclass UserlandActionChecker(base.ActionChecker):
45N/A """An opensolaris.org-specific class to check actions."""
45N/A
45N/A name = "userland.action"
45N/A
45N/A def __init__(self, config):
45N/A self.description = _(
45N/A "checks Userland packages for common content errors")
117N/A self.prototype = os.getenv('PROTO_DIR')
117N/A self.runpath_re = [
117N/A re.compile('^/lib(/.*)?$'),
117N/A re.compile('^/usr/'),
117N/A re.compile('^\$ORIGIN/')
1531N/A ]
1531N/A self.initscript_re = re.compile("^etc/(rc.|init)\.d")
1531N/A super(UserlandActionChecker, self).__init__(config)
1531N/A
1531N/A def startup(self, engine):
1531N/A if self.prototype != None:
1531N/A engine.info(_("including prototype checks: %s") %
1531N/A self.prototype, msgid=self.name)
1531N/A
1531N/A def __realpath(self, path, target):
1531N/A """Combine path and target to get the real path."""
1531N/A
1531N/A result = os.path.dirname(path)
1531N/A
1531N/A for frag in target.split(os.sep):
1531N/A if frag == '..':
1531N/A result = os.path.dirname(result)
1531N/A elif frag == '.':
45N/A pass
99N/A else:
45N/A result = os.path.join(result, frag)
45N/A
45N/A return result
634N/A
634N/A def __elf_runpath_check(self, path):
634N/A result = None
1531N/A list = []
1531N/A
1531N/A ed = elf.get_dynamic(path)
634N/A for dir in ed.get("runpath", "").split(":"):
84N/A if dir == None or dir == '':
186N/A continue
186N/A
186N/A match = False
186N/A for expr in self.runpath_re:
45N/A if expr.match(dir):
45N/A match = True
186N/A break
186N/A
186N/A if match == False:
186N/A list.append(dir)
186N/A
186N/A if len(list) > 0:
186N/A result = _("bad RUNPATH, '%%s' includes '%s'" %
186N/A ":".join(list))
186N/A
186N/A return result
186N/A
186N/A def __elf_wrong_location_check(self, path):
186N/A result = None
186N/A
186N/A ei = elf.get_info(path)
186N/A bits = ei.get("bits")
186N/A frag = os.path.basename(os.path.dirname(path))
186N/A
186N/A if bits == 32 and frag in ["sparcv9", "amd64", "64"]:
186N/A result = _("32-bit object '%s' in 64-bit path")
186N/A elif bits == 64 and frag not in ["sparcv9", "amd64", "64"]:
186N/A result = _("64-bit object '%s' in 32-bit path")
186N/A
186N/A return result
186N/A
186N/A def file_action(self, action, manifest, engine, pkglint_id="001"):
186N/A """Checks for existence in the proto area."""
186N/A
186N/A if action.name not in ["file"]:
186N/A return
186N/A
186N/A path = action.attrs["path"]
186N/A
186N/A # check for writable files without a preserve attribute
186N/A if 'mode' in action.attrs:
186N/A mode = action.attrs["mode"]
186N/A
186N/A if (int(mode, 8) & 0222) != 0 and "preserve" not in action.attrs:
186N/A engine.error(
186N/A _("%(path)s is writable (%(mode)s), but missing a preserve"
186N/A " attribute") % {"path": path, "mode": mode},
186N/A msgid="%s%s.0" % (self.name, pkglint_id))
186N/A
186N/A # checks that require a physical file to look at
186N/A if self.prototype is not None:
186N/A fullpath = self.prototype + "/" + path
186N/A
186N/A if not os.path.exists(fullpath):
186N/A engine.info(
186N/A _("%s missing from proto area, skipping"
186N/A " content checks") % path,
186N/A msgid="%s%s.1" % (self.name, pkglint_id))
186N/A elif elf.is_elf_object(fullpath):
186N/A # 32/64 bit in wrong place
186N/A result = self.__elf_wrong_location_check(fullpath)
186N/A if result != None:
186N/A engine.error(result % path,
186N/A msgid="%s%s.2" % (self.name, pkglint_id))
186N/A result = self.__elf_runpath_check(fullpath)
186N/A if result != None:
186N/A engine.error(result % path,
186N/A msgid="%s%s.3" % (self.name, pkglint_id))
186N/A
186N/A file_action.pkglint_desc = _("Paths should exist in the proto area.")
186N/A
186N/A def link_resolves(self, action, manifest, engine, pkglint_id="002"):
186N/A """Checks for link resolution."""
186N/A
186N/A if action.name not in ["link", "hardlink"]:
186N/A return
186N/A
186N/A path = action.attrs["path"]
186N/A target = action.attrs["target"]
186N/A realtarget = self.__realpath(path, target)
186N/A
186N/A resolved = False
186N/A for maction in manifest.gen_actions():
186N/A mpath = None
186N/A if maction.name in ["dir", "file", "link",
186N/A "hardlink"]:
186N/A mpath = maction.attrs["path"]
186N/A
186N/A if mpath and mpath == realtarget:
186N/A resolved = True
186N/A break
186N/A
186N/A if resolved != True:
186N/A engine.error(
186N/A _("%s %s has unresolvable target '%s'") %
186N/A (action.name, path, target),
186N/A msgid="%s%s.0" % (self.name, pkglint_id))
186N/A
186N/A link_resolves.pkglint_desc = _("links should resolve.")
186N/A
186N/A def init_script(self, action, manifest, engine, pkglint_id="003"):
186N/A """Checks for SVR4 startup scripts."""
186N/A
186N/A if action.name not in ["file", "dir", "link", "hardlink"]:
186N/A return
186N/A
186N/A path = action.attrs["path"]
186N/A if self.initscript_re.match(path):
186N/A engine.warning(
186N/A _("SVR4 startup '%s', deliver SMF"
186N/A " service instead") % path,
186N/A msgid="%s%s.0" % (self.name, pkglint_id))
186N/A
186N/A init_script.pkglint_desc = _(
186N/A "SVR4 startup scripts should not be delivered.")
186N/A
186N/Aclass UserlandManifestChecker(base.ManifestChecker):
186N/A """An opensolaris.org-specific class to check manifests."""
186N/A
186N/A name = "userland.manifest"
186N/A
186N/A def __init__(self, config):
186N/A self.prototype = os.getenv('PROTO_DIR')
186N/A super(UserlandManifestChecker, self).__init__(config)
186N/A
186N/A def license_check(self, manifest, engine, pkglint_id="001"):
186N/A manifest_paths = []
186N/A files = False
84N/A license = False
84N/A
84N/A for action in manifest.gen_actions_by_type("file"):
84N/A files = True
84N/A break
84N/A
84N/A if files == False:
84N/A return
84N/A
84N/A for action in manifest.gen_actions_by_type("license"):
84N/A return
84N/A
84N/A engine.error( _("missing license action"),
84N/A msgid="%s%s.0" % (self.name, pkglint_id))
84N/A
84N/A license_check.pkglint_dest = _(
634N/A "license actions are required if you deliver files.")
84N/A