#!/bin/sh # NAME: # meta2deps.sh - extract useful info from .meta files # # SYNOPSIS: # meta2deps.sh SB="SB" "meta" ... # # DESCRIPTION: # This script looks each "meta" file and extracts the # information needed to deduce build and src dependencies. # # To do this, we extract the 'CWD' record as well as all the # syscall traces which describe 'R'ead, 'C'hdir and 'E'xec # syscalls. # # The typical meta file looks like:: #.nf # # # Meta data file "path" # CMD "command-line" # CWD "cwd" # TARGET "target" # -- command output -- # -- filemon acquired metadata -- # # buildmon version 2 # V 2 # E "pid" "path" # R "pid" "path" # C "pid" "cwd" # R "pid" "path" # X "pid" "status" #.fi # # The fact that all the syscall entry lines start with a single # character make these files quite easy to process using sed(1). # # To simplify the logic the 'CWD' line is made to look like a # normal 'C'hdir entry, and "cwd" is remembered so that it can # be prefixed to any "path" which is not absolute. # # If the "path" being read ends in '.srcrel' it is the content # of (actually the first line of) that file that we are # interested in. # # Any "path" which lies outside of the sandbox "SB" is generally # not of interest and is ignored. # # The output, is a set of absolute paths with "SB" like: #.nf # # $SB/obj-i386/bsd/gnu/lib/csu # $SB/obj-i386/bsd/gnu/lib/libgcc # $SB/obj-i386/bsd/include # $SB/obj-i386/bsd/lib/csu/i386 # $SB/obj-i386/bsd/lib/libc # $SB/src/bsd/include # $SB/src/bsd/sys/i386/include # $SB/src/bsd/sys/sys # $SB/src/pan-release/rtsock # $SB/src/pfe-shared/include/jnx #.fi # # Which can then be further processed by 'gendirdeps.mk' # # If we are passed 'DPDEPS='"dpdeps", then for each src file # outside of "CURDIR" we read, we output a line like: #.nf # # DPDEPS_$path += $RELDIR #.fi # # with "$path" geting turned into reldir's, so that we can end # up with a list of all the directories which depend on each src # file in another directory. This can allow for efficient yet # complete testing of changes. # RCSid: # $Id: meta2deps.sh,v 1.12 2016/12/13 20:44:16 sjg Exp $ # Copyright (c) 2010-2013, Juniper Networks, Inc. # All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # 1. Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # 2. Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in the # documentation and/or other materials provided with the distribution. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. proc meta2src { cat /dev/null @Argv | sed -n '/^R .*\.[chyl]$/s,^..[0-9]* ,,p' | sort -u } proc meta2dirs { cat /dev/null @Argv | sed -n '/^R .*\/.*\.[a-z0-9][^\/]*$/s,^..[0-9]* \(.*\)/[^/]*$,\1,p' | sort -u } proc add_list { setglobal sep = '' '' setglobal suffix = '' while : { match $1 { with "|" setglobal sep = $1; shift with -s setglobal suffix = $2; shift 2 with * break } } setglobal name = $1 shift eval list="\$$name" for top in [@Argv] { match "$sep$list$sep" { with *"$sep$top$suffix$sep"* continue } setglobal list = ""$(list:+$list$sep)$top$suffix"" } eval "$name=\"$list\"" } proc _excludes_f { egrep -v $EXCLUDES } proc meta2deps { setglobal DPDEPS = '' setglobal SRCTOPS = $SRCTOP setglobal OBJROOTS = '' setglobal EXCLUDES = '' while : { match $1 { with *=* eval export $1; shift with -a setglobal MACHINE_ARCH = $2; shift 2 with -m setglobal MACHINE = $2; shift 2 with -C setglobal CURDIR = $2; shift 2 with -H setglobal HOST_TARGET = $2; shift 2 with -S add_list SRCTOPS $2; shift 2 with -O add_list OBJROOTS $2; shift 2 with -X add_list EXCLUDES '|' $2; shift 2 with -R setglobal RELDIR = $2; shift 2 with -T setglobal TARGET_SPEC = $2; shift 2 with * break } } setglobal _th = '', _o = '' match $MACHINE { with host setglobal _ht = $HOST_TARGET } for o in [$OBJROOTS] { match "$MACHINE,/$o/" { with host,*$HOST_TARGET* with *$MACHINE*|*${TARGET_SPEC:-$MACHINE}* with * add_list _o $o; continue } for x in [$_ht $TARGET_SPEC $MACHINE] { match $o { with "" continue with */$x/ add_list _o $(o%$x/); setglobal o = '' with */$x add_list _o $(o%$x); setglobal o = '' with *$x/ add_list _o $(o%$x/); setglobal o = '' with *$x add_list _o $(o%$x); setglobal o = '' } } } setglobal OBJROOTS = $_o match $OBJTOP { with "" for o in [$OBJROOTS] { setglobal OBJTOP = "$o$(TARGET_SPEC:-$MACHINE)" break } } setglobal src_re = '' setglobal obj_re = '' add_list '|' -s '/*' src_re $SRCTOPS add_list '|' -s '*' obj_re $OBJROOTS test -z $RELDIR && unset DPDEPS setglobal tf = "/tmp/m2d$Pid-$USER" rm -f $tf.* trap 'rm -f $tf.*; trap 0' 0 > $tf.dirdep > $tf.qual > $tf.srcdep > $tf.srcrel > $tf.dpdeps setglobal seenit = '' setglobal seensrc = '' setglobal lpid = '' match $EXCLUDES { with "" setglobal _excludes = 'cat' with * setglobal _excludes = '_excludes_f' } # handle @list files match @Argv { with *@[!.]* for f in [@Argv] { match $f { with *.meta cat $f with @* xargs cat < $(f#@) with * cat $f } } with * cat /dev/null @Argv } 2> /dev/null | sed -e 's,^CWD,C C,;/^[CREFLM] /!d' -e "s,',,g" | $_excludes | while read op pid path junk { : op=$op pid=$pid path=$path # we track cwd and ldir (of interest) per pid # CWD is bmake's cwd match "$lpid,$pid" { with ,C setglobal CWD = $path, cwd = $path, ldir = $path if test -z $SB { setglobal SB = $[echo $CWD | sed 's,/obj.*,,] } setglobal SRCTOP = $(SRCTOP:-$SB/src) continue with $pid,$pid with * match $lpid { with "" with * eval ldir_$lpid=$ldir } eval ldir='$'{ldir_$pid:-$CWD} cwd='$'{cwd_$pid:-$CWD} setglobal lpid = $pid } match "$op,$path" { with W,*srcrel|*.dirdep continue with C,* match $path { with /* setglobal cwd = $path with * setglobal cwd = $[cd $cwd/$path !2 > /dev/null && /bin/pwd] } # watch out for temp dirs that no longer exist test -d $(cwd:-/dev/null/no/such) || setglobal cwd = $CWD eval cwd_$pid=$cwd continue with F,* # $path is new pid eval cwd_$path=$cwd ldir_$path=$ldir continue with * setglobal dir = $(path%/*) match $path { with $src_re|$obj_re with /*/stage/* with /* continue with * for path in [$ldir/$path $cwd/$path] { test -e $path && break } setglobal dir = $(path%/*) } } # avoid repeating ourselves... match "$DPDEPS,$seensrc," { with ,* match ",$seenit," { with *,$dir,* continue } with *,$path,* continue } # canonicalize if needed match "/$dir/" { with */../*|*/./* setglobal rdir = $dir setglobal dir = $[cd $dir !2 > /dev/null && /bin/pwd] setglobal seen = ""$rdir,$dir"" with * setglobal seen = $dir } match $dir { with ${CURDIR:-.}|"" continue with $src_re # avoid repeating ourselves... match "$DPDEPS,$seensrc," { with ,* match ",$seenit," { with *,$dir,* continue } } with * match ",$seenit," { with *,$dir,* continue } } if test -d $path { match $path { with */.. setglobal ldir = $(dir%/*) with * setglobal ldir = $path } continue } test -f $path || continue match $dir { with $CWD continue # ignore with $src_re setglobal seenit = ""$seenit,$seen"" echo $dir >> $tf.srcdep match "$DPDEPS,$reldir,$seensrc," { with ,* with * setglobal seensrc = ""$seensrc,$path"" echo "DPDEPS_$dir/$(path##*/) += $RELDIR" >> $tf.dpdeps } continue } # if there is a .dirdep we cannot skip # just because we've seen the dir before. if test -s $path.dirdep { # this file contains: # '# ${RELDIR}.' echo $path.dirdep >> $tf.qual continue } elif test -s $dir.dirdep { echo $dir.dirdep >> $tf.qual setglobal seenit = ""$seenit,$seen"" continue } setglobal seenit = ""$seenit,$seen"" match $dir { with $obj_re echo $dir } } > $tf.dirdep setglobal _nl = 'echo' for f in [$tf.dirdep $tf.qual $tf.srcdep] { test -s $f || continue match $f { with *qual # a list of .dirdep files # we can prefix everything with $OBJTOP to # tell gendirdeps.mk that these are # DIRDEP entries, since they are already # qualified with . as needed. # We strip .$MACHINE though xargs cat < $f | sort -u | sed "s,^# ,,;s,^,$OBJTOP/,;s,\.$(TARGET_SPEC:-$MACHINE)\$,,;s,\.$MACHINE\$,," with * sort -u $f } setglobal _nl = ':' } if test -s $tf.dpdeps { match $DPDEPS { with */* with * echo > $DPDEPS # the echo is needed! } sort -u $tf.dpdeps | sed "s,$(SRCTOP)/,,;s,$(SB_BACKING_SB:-$SB)/src/,," >> $DPDEPS } # ensure we produce _something_ else egrep -v gets upset $_nl } match /$0 { with */meta2dep* meta2deps @Argv with */meta2dirs* meta2dirs @Argv with */meta2src* meta2src @Argv }