#!/bin/ksh93 PROG=${0##*/} function usage { cat >&${1:-2} <SPSPSPSPSP # Parse a /var/sadm/install/contents file function prep_src_svr4_contents { typeset dst dst=$1 shift print " processing SVR4 contents file ${1}..." grep ' [fev] ' "$1" | cut -d\ -f1,10 | \ sed -e 's,^/\([^ ]*\)/\([^ ]*\) \(.*\),file \2 \1/\2 NULL \3,' \ -e "s,\$, ${2:-WOS}," > "$dst" grep ' [l] ' "$1" | cut -d\ -f1,4 | \ sed -e 's,^/\([^=]*\)=\([^ ]*\) \(.*\),link NULL \1 \2 \3,' \ -e "s,\$, ${2:-WOS}," >> "$dst" } # Parse a Product directory function prep_src_svr4_pkgs { typeset dst dst=$1 shift print " processing SVR4 Product directory ${1}..." find "$1" -name pkgmap | xargs grep ' [fev] ' | \ tr : ' ' | cut -d\ -f1,5| \ sed -e 's,^\([^ ]*\)/pkgmap \(.*\)/\(.*\)$,file \3 \2/\3 NULL \1,' \ -e "s,\$, ${2:-WOS}," > "$dst" find "$1" -name pkgmap | xargs grep ' [l] ' | \ tr : ' ' | cut -d\ -f1,5| \ sed -e 's,^\([^ ]*\)/pkgmap \([^=].*\)/=\(.*\)$,link NULL \2 \3 \1,' \ -e "s,\$, ${2:-WOS}," >> "$dst" } # Parse either a /var/sadm/install/contents file or Product dir function prep_src_svr4 { if [[ "$2" = "-" ]] then prep_src_svr4_contents "$1" $v4_contents elif [[ -f "$2" ]] then prep_src_svr4_contents "$@" elif [[ -d "$2" ]] then prep_src_svr4_pkgs "$@" else usage fi } # Parse IPS pkg meta-data function prep_src_ips { typeset dst p n a b dst=$1 shift if [[ "$1" = "-" ]] then print " processing IPS metadata for current image..." pkg contents -H -o action.key,pkg.name,pkg.authority -t file | ( set +x while read p n a do print -r "file ${p##*/} $p NULL $n $a" done ) > "$dst" #sed -e 's,^\([^ ]*\)/\([^/]*\) \([^ ]*\) \(.*\)$,\2 \1/\2 \3 \4,' pkg contents -H -o path,target,pkg.name,pkg.authority -t link | ( set +x while read p t n a do print -r "link NULL $p $t $n $a" done ) >> "$dst" elif [[ -f "$1" ]] then print " processing IPS metadata in ${1}..." set +x while read p n a do print -r "file ${p##*/} $p NULL $n $a" done < "$1" > "$dst" $debug && set -x else # This looks through a dir that contains dirs named # after pkgs and which contain manifests. I.e., like # /var/pkg/repo/pkg. # # The find ...| xargs grep ... pipe produces lines like: # /:file...path=... print " processing IPS metadata in depot directory ${1}..." ( cd "$1" > /dev/null find . -type f | xargs grep ^file /dev/null | \ sed -e 's,^\./\([^/]*\)/[^:]*:\(.*\)$,\1:\2,' \ -e 's,^\([^:]*\):file.*path=\([^ ]*\) .*$,\2 \1,' \ -e 's,^\([^ ]*\)/\([^ ]*\) \([^/]*\)$,file \2 \1/\2 NULL \3,' \ -e "s,\$, ${2:-opensolaris.org}," > "$dst" find . -type f | xargs grep ^link /dev/null | \ sed -e 's,^\./\([^/]*\)/[^:]*:\(.*\)$,\1:\2,' \ -e 's,^\([^:]*\):link.*path=\([^ ]*\) target=\([^ ]*\),link NULL \2 \3 \1,' \ -e "s,\$, ${2:-opensolaris.org}," >> "$dst" ) fi } function create_views { db=$1 $ptime sqlite3 "$db" < 1 ORDER BY c DESC; CREATE VIEW conf_basenames AS SELECT c, basename, pkg FROM (SELECT count(DISTINCT pkg) AS c, basename, group_concat(DISTINCT pkg) AS pkg FROM paths WHERE action = 'file' GROUP BY basename) WHERE c > 1 ORDER BY c DESC; CREATE VIEW conf_sonames AS SELECT c, soname, pkg FROM (SELECT count(DISTINCT pkg) AS c, rtrim(basename, '.0123456789') AS soname, group_concat(DISTINCT pkg) AS pkg FROM paths WHERE basename like 'lib%.so.%' AND action = 'file' GROUP BY rtrim(basename, '.0123456789')) WHERE c > 1 ORDER BY c DESC; EOF } typeset -l typ v4_contents=/var/sadm/install/contents def_ips_data="$(/bin/pwd)/manifests" [[ -d "$def_ips_data" ]] || def_ips_data=/var/pkg/repo/pkg def_wos_data="/var/sadm/install/contents" interact=false output_dir=$(/bin/pwd) db=$(/bin/pwd)/db debug=false load=false analyze=false clobber_db=false delete_dups=: conf_basename_cutoff=100 # Yes, this should be made to use getopts. while [[ $# -gt 0 ]] do case "$1" in load) load=: shift while [[ $# -gt 0 ]] do case "$1" in -x) debug=: typeset -ft $(typeset +f|awk '{print $1}') set -x;; -c) clobber_db=:;; -o) db=$2; shift;; -s) if [[ "$2" = local ]] then if [[ -s $v4_contents ]] then add_src svr4 $v4_contents WOS else add_src ips - - fi shift elif [[ "$2" = svr4 && "$3" = "-" ]] then add_src $2 - WOS shift 2 elif [[ "$2" = ips ]] then add_src $2 "$3" - shift 2 else [[ $# -ge 4 || "$2" != svr4 ]] || usage add_src "$2" "$3" "$4" shift 3 fi ;; *) usage 1;; esac shift done ;; analyze) analyze=: shift while [[ $# -gt 0 ]] do case "$1" in -x) debug=: typeset -ft $(typeset +f|awk '{print $1}') set -x;; -D) delete_dups=false;; -i) interact=:;; -o) output_dir=$2; db=$output_dir/db; shift;; -*) usage 1;; *) db=$1; shift; break;; esac shift done [[ $# -gt 0 ]] && usage 1 if [[ ! -f $db ]] then print -u2 "Error: must load the data first" usage fi ;; *) usage 1;; esac done [[ $# -gt 0 ]] && usage $load || $analyze || usage if $clobber_db && [[ -f "$db" ]] then rm -f "$db" fi if $load then if ((${srcs.num} == 0)) then usage fi print "Loading pkg data into $db..." file_pkg_list=$(mktemp /tmp/file_pkg_list_XXXXX) if [[ -z "$file_pkg_list" ]] then print -u2 "Error: Could not create temporary files" exit 1 fi sqlite3 "$db" "CREATE TABLE IF NOT EXISTS paths( action TEXT NOT NULL, basename TEXT, path TEXT NOT NULL, target TEXT, pkg TEXT NOT NULL, pkg_typ TEXT NOT NULL, repo TEXT NOT NULL );" sqlite3 "$db" "DROP INDEX IF EXISTS basename;" sqlite3 "$db" "DROP INDEX IF EXISTS path;" integer i=0 while [[ $i < ${srcs.num} ]] do nameref src="srcs.s${i}" ((i+=1)) typ=${src[0]} loc=${src[1]} repo=${src[2]} if [[ -z "$typ" ]] then print -u2 "Error: internal error" exit 2 fi prep_src_$typ "$file_pkg_list" "$loc" "$repo" pop_db "$db" "$file_pkg_list" "$typ" cat /dev/null > $file_pkg_list done print " creating various views ..." create_views "$db" fi if ! $analyze then exit 0 fi set -A ofiles -- conf_pkgs_by_path conf_pkgs_by_basename conf_pkgs_by_soname \ conf_paths conf_pkg_pairs conf_basenames conf_sonames \ conf_pkg_pairs_similar for i in "${ofiles[@]}" do [[ -f "$output_dir/$i" ]] || continue if $interact then typeset -l ans print -n "Clean up existing analysis? (y/n) " read ans case "$ans" in y|yes) for i in "${files[@]}" do rm -f "$output_dir/$i" done ;; *) exit 1;; esac else for i in "${files[@]}" do rm -f "$output_dir/$i" done fi break done print "Analyzing data..." print " creating indexes..." $ptime sqlite3 "$db" < length(pkg1) AND lower(pkg1) = substr(lower(pkg2), 0, length(pkg1))) OR (length(pkg1) > length(pkg2) AND lower(pkg2) = substr(lower(pkg1), 0, length(pkg2))); .output stdout SELECT count(*) AS "Conflicting PKG lists" FROM conf_pkgs_by_path; SELECT count(*) AS "All PKG pairs with one or more conflicting paths" FROM conf_pkg_pairs; SELECT count(*) AS "Conflicting PKG pairs differing only in case" FROM conf_pkg_pairs WHERE lower(pkg1) = lower(pkg2); SELECT count(*) AS "Conflicting PKG pairs differing in case and prefix or suffix" FROM conf_pkg_pairs WHERE (length(pkg2) > length(pkg1) AND lower(pkg1) = substr(lower(pkg2), 0, length(pkg1))) OR (length(pkg1) > length(pkg2) AND lower(pkg2) = substr(lower(pkg1), 0, length(pkg2))); EOF cat <