1#!/bin/sh 2 3set -u 4 5ME=$(basename $0) 6 7USAGE="Usage: ${ME} {options} 8 9Builds a license metadata specification and outputs it to stdout or {outfile}. 10 11The available options are: 12 13-k kind... license kinds 14-c condition... license conditions 15-p package... license package name 16-n notice... license notice file 17-d dependency... license metadata file dependency 18-t target... targets 19-m target:installed... map dependent targets to their installed names 20-is_container preserved dependent target name when given 21-o outfile output file 22" 23 24# Global flag variables 25license_kinds= 26license_conditions= 27license_package_name= 28license_notice= 29license_deps= 30targets= 31installmap= 32is_container=false 33ofile= 34 35# Global variables 36depfiles=" " 37effective_conditions= 38 39 40# Exits with a message. 41# 42# When the exit status is 2, assumes a usage error and outputs the usage message 43# to stderr before outputting the specific error message to stderr. 44# 45# Parameters: 46# Optional numeric exit status (defaults to 2, i.e. a usage error.) 47# Remaining args treated as an error message sent to stderr. 48die() { 49 lstatus=2 50 case "${1:-}" in *[^0-9]*) ;; *) lstatus="$1"; shift ;; esac 51 case "${lstatus}" in 2) echo "${USAGE}" >&2; echo >&2 ;; esac 52 if [ -n "$*" ]; then 53 echo -e "$*\n" >&2 54 fi 55 exit $lstatus 56} 57 58 59# Sets the flag variables based on the command-line. 60# 61# invoke with: process_args "$@" 62process_args() { 63 lcurr_flag= 64 while [ "$#" -gt '0' ]; do 65 case "${1}" in 66 -h) 67 echo "${USAGE}" 68 exit 0 69 ;; 70 -k) 71 lcurr_flag=kind 72 ;; 73 -c) 74 lcurr_flag=condition 75 ;; 76 -p) 77 lcurr_flag=package 78 ;; 79 -n) 80 lcurr_flag=notice 81 ;; 82 -d) 83 lcurr_flag=dependency 84 ;; 85 -t) 86 lcurr_flag=target 87 ;; 88 -m) 89 lcurr_flag=installmap 90 ;; 91 -o) 92 lcurr_flag=ofile 93 ;; 94 -is_container) 95 lcurr_flag= 96 is_container=true 97 ;; 98 -*) 99 die "Unknown flag: \"${1}\"" 100 ;; 101 *) 102 case "${lcurr_flag}" in 103 kind) 104 license_kinds="${license_kinds}${license_kinds:+ }${1}" 105 ;; 106 condition) 107 license_conditions="${license_conditions}${license_conditions:+ }${1}" 108 ;; 109 package) 110 license_package_name="${license_package_name}${license_package_name:+ }${1}" 111 ;; 112 notice) 113 license_notice="${license_notice}${license_notice:+ }${1}" 114 ;; 115 dependency) 116 license_deps="${license_deps}${license_deps:+ }${1}" 117 ;; 118 target) 119 targets="${targets}${targets:+ }${1}" 120 ;; 121 installmap) 122 installmap="${installmap}${installmap:+ }${1}" 123 ;; 124 ofile) 125 if [ -n "${ofile}" ]; then 126 die "Output file -o appears twice as \"${ofile}\" and \"${1}\"" 127 fi 128 ofile="${1}" 129 ;; 130 *) 131 die "Must precede argument \"${1}\" with type flag." 132 ;; 133 esac 134 ;; 135 esac 136 shift 137 done 138} 139 140# Reads a license metadata file from stdin, and outputs the named dependencies. 141# 142# No parameters. 143extract_deps() { 144 awk '$1 == "dep_name:" { sub(/^"/, "", $2); sub(/"$/, "", $2); print $2; }' 145} 146 147# Populates the depfiles variable identifying dependency files. 148# 149# Starting with the dependencies enumerated in license_deps, calculates the 150# transitive closure of all dependencies. 151# 152# Dependency names ending in .meta_module indirectly reference license 153# metadata with 1 license metadata filename per line. 154# 155# No parameters; no output. 156read_deps() { 157 lnewdeps= 158 for d in ${license_deps}; do 159 case "${d}" in 160 *.meta_module) 161 lnewdeps="${lnewdeps}${lnewdeps:+ }"$(cat "${d}") ;; 162 *) 163 lnewdeps="${lnewdeps}${lnewdeps:+ }${d}" ;; 164 esac 165 done 166 lnewdeps=$(echo "${lnewdeps}" | tr ' ' '\n' | sort -u) 167 lalldeps= 168 ldeps= 169 lmod= 170 ldep= 171 while [ "${#lnewdeps}" -gt '0' ]; do 172 ldeps="${lnewdeps}" 173 lnewdeps= 174 for ldep in ${ldeps}; do 175 depfiles="${depfiles}${ldep} " 176 lalldeps="${lalldeps}${lalldeps:+ }"$(cat "${ldep}" | extract_deps) 177 done 178 lalldeps=$(for d in ${lalldeps}; do echo "${d}"; done | sort -u) 179 for d in ${lalldeps}; do 180 ldeps="${d}" 181 case "${d}" in *.meta_module) ldeps=$(cat "${d}") ;; esac 182 for lmod in ${ldeps}; do 183 if ! expr "${depfiles}" : ".* ${lmod} .*" >/dev/null 2>&1; then 184 lnewdeps="${lnewdeps}${lnewdeps:+ }${lmod}" 185 fi 186 done 187 done 188 lalldeps= 189 done 190} 191 192# Returns the effective license conditions for the current license metadata. 193# 194# If a module is restricted or links in a restricted module, the effective 195# license has a restricted condition. 196calculate_effective_conditions() { 197 lconditions="${license_conditions}" 198 case "${license_conditions}" in 199 *restricted*) : do nothing ;; 200 *) 201 for d in ${depfiles}; do 202 if cat "${d}" | egrep -q 'effective_condition\s*:.*restricted' ; then 203 lconditions="${lconditions}${lconditions:+ }restricted" 204 break 205 fi 206 done 207 ;; 208 esac 209 echo "${lconditions}" 210} 211 212 213process_args "$@" 214 215if [ -n "${ofile}" ]; then 216 # truncate the output file before appending results 217 : >"${ofile}" 218else 219 ofile=/dev/stdout 220fi 221 222# spit out the license metadata file content 223( 224 echo 'license_package_name: "'${license_package_name}'"' 225 for kind in ${license_kinds}; do 226 echo 'license_kind: "'${kind}'"' 227 done 228 for condition in ${license_conditions}; do 229 echo 'license_condition: "'${condition}'"' 230 done 231 for f in ${license_notice}; do 232 echo 'license_text: "'${f}'"' 233 done 234 echo "is_container: ${is_container}" 235 for t in ${targets}; do 236 echo 'target: "'${t}'"' 237 done 238 for m in ${installmap}; do 239 echo 'install_map: "'${m}'"' 240 done 241) >>"${ofile}" 242read_deps 243effective_conditions=$(calculate_effective_conditions) 244for condition in ${effective_conditions}; do 245 echo 'effective_condition: "'${condition}'"' 246done >>"${ofile}" 247for dep in ${depfiles}; do 248 echo 'dep {' 249 cat "${dep}" | \ 250 awk -v name="${dep}" ' 251 function strip_type() { 252 $1 = "" 253 sub(/^\s*/, "") 254 } 255 BEGIN { 256 print " dep_name: " name 257 } 258 $1 == "license_package_name:" { 259 strip_type() 260 print " dep_package_name: "$0 261 } 262 $1 == "dep_name:" { 263 print " dep_sub_dep: "$2 264 } 265 $1 == "license_kind:" { 266 print " dep_license_kind: "$2 267 } 268 $1 == "license_condition:" { 269 print " dep_license_condition: "$2 270 } 271 $1 == "is_container:" { 272 print " dep_is_container: "$2 273 } 274 $1 == "license_text:" { 275 strip_type() 276 print " dep_license_text: "$0 277 } 278 $1 == "target:" { 279 print " dep_target: "$2 280 } 281 $1 == "install_map:" { 282 print " dep_install_map: "$2 283 } 284 ' 285 # The restricted license kind is contagious to all linked dependencies. 286 dep_conditions=$(echo $( 287 cat "${dep}" | awk ' 288 $1 == "effective_condition:" { 289 $1 = "" 290 sub(/^\s*/, "") 291 gsub(/"/, "") 292 print 293 } 294 ' 295 )) 296 for condition in ${dep_conditions}; do 297 echo ' dep_effective_condition: "'${condition}'"' 298 done 299 if ! ${is_container}; then 300 case "${dep_conditions}" in 301 *restricted*) : already restricted -- nothing to inherit ;; 302 *) 303 case "${effective_conditions}" in 304 *restricted*) 305 # "contagious" restricted infects everything linked to restricted 306 echo ' dep_effective_condition: "restricted"' 307 ;; 308 esac 309 ;; 310 esac 311 fi 312 echo '}' 313done >>"${ofile}" 314