1#!/usr/bin/awk -f 2 3# 4# Copyright (c) 2015 M. Warner Losh. 5# All rights reserved. 6# 7# Redistribution and use in source and binary forms, with or without 8# modification, are permitted provided that the following conditions 9# are met: 10# 1. Redistributions of source code must retain the above copyright 11# notice, this list of conditions and the following disclaimer. 12# 2. Redistributions in binary form must reproduce the above copyright 13# notice, this list of conditions and the following disclaimer in the 14# documentation and/or other materials provided with the distribution. 15# 16# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26# SUCH DAMAGE. 27# 28# $FreeBSD$ 29# 30 31# 32# Takes a meta-log created by installworld and friends, plus 33# additions from NanoBSD to augment its build to communicate when 34# files move around after installworld / installkernel phase of 35# NanoBSD. 36# 37# All mtree lines from the metafile have a path, followed by 38# a number of keywords. 39# 40# This script recognizes the following new keywords 41# 42# unlink[=x] remove the path from the output. 43# copy_from=x create new entry for path copied from 44# the keywords from x. 45# move_from=x create new entry for path copied from 46# the keywords from x. Remove path from 47# the output. 48# 49# In addition, when path matches a previous entry, the 50# new entry and previous entry are merged. 51# 52# Special note: when uid and uname are both present, 53# uid is ignored. Ditto gid/gname. 54# 55# Also, the paths above have to match exactly, so X 56# should start with "./". 57# 58 59function die(str) 60{ 61 print str > "/dev/stderr"; 62 exit 1; 63} 64 65function kv(str) 66{ 67 if (split(str, xxx, "=") == 2) { 68 kv_key = xxx[1]; 69 kv_value = xxx[2]; 70 } else { 71 kv_key = str; 72 kv_value = nv; 73 } 74} 75 76# Output the mtree for path based on the kvs. 77function mtree_from_kvs(path, kvs) 78{ 79 lv = path " "; 80 for (k in kvs) { 81 if (kvs[k] == nv) 82 lv = lv k " "; 83 else 84 lv = lv k "=" kvs[k] " "; 85 } 86 return lv; 87} 88 89# Parse the mtree line into path + KVs. Use a sentinal value 90# for a bare keyword, which is extremely unlikely to be used 91# for real. 92function line2kv(kvs, str) 93{ 94 delete kvs; 95 96 n = split(str, yyy, " "); 97 for (i = 2; i <= n; i++) { 98 s = yyy[i]; 99 if (split(s, xxx, "=") == 2) 100 kvs[xxx[1]] = xxx[2]; 101 else 102 kvs[s] = nv; 103 } 104} 105 106 107# old += new 108function merge_kvs(old, new) 109{ 110 for (k in new) { 111 # uname / uid -- last one wins. 112 if (k == "uid" && "uname" in old) 113 delete old["uname"] 114 if (k == "uname" && "uid" in old) 115 delete old["uid"]; 116 # gname / gid -- last one wins. 117 if (k == "gid" && "gname" in old) 118 delete old["gname"] 119 if (k == "gname" && "gid" in old) 120 delete old["gid"]; 121 # Otherwise newest value wins 122 old[k] = new[k]; 123 } 124} 125 126# Process the line we've read in, per the comments below 127function process_line(path, new) 128{ 129 # Clear kvs 130 line2kv(new_kvs, new); 131 132 if ("unlink" in new_kvs) { 133 # A file removed 134 # Sanity check to see if tree[path] exists? 135 # Makes sure when foo/bar/baz exists and foo/bar 136 # unlinked, baz is gone (for all baz). 137 if (path !~ "^\./") 138 die("bad path in : " new); 139 delete tree[path]; # unlink 140 return; 141 # } else if (new_kvs["append_from"]) { # not implemented 142 } else if ("copy_from" in new_kvs) { 143 # A file copied from another location, preserve its 144 # attribute for new file. 145 # Also merge any new attributes from this line. 146 from = new_kvs["copy_from"]; 147 if (from !~ "^\./") 148 die("bad path in : " new); 149 delete new_kvs["copy_from"]; 150 line2kv(old_kvs, tree[from]); # old_kvs = kv's in entry 151 merge_kvs(old_kvs, new_kvs); # old_kvs += new_kvs 152 tree[path] = mtree_from_kvs(path, old_kvs); 153 } else if ("move_from" in new_kvs) { 154 # A file moved from another location, preserve its 155 # attribute for new file, and scrag old location 156 # Also merge any new attributes from this line. 157 from = new_kvs["move_from"]; 158 if (from !~ "^\./") 159 die("bad path in : " new); 160 delete new_kvs["move_from"]; 161 line2kv(old_kvs, tree[from]); # old_kvs = kv's in entry 162 merge_kvs(old_kvs, new_kvs); # old_kvs += new_kvs 163 tree[path] = mtree_from_kvs(path, old_kvs); 164 delete tree[from]; # unlink 165 } else if (tree[path]) { # Update existing entry with new line 166 line2kv(old_kvs, tree[path]); # old_kvs = kv's in entry 167 merge_kvs(old_kvs, new_kvs); # old_kvs += new_kvs 168 tree[path] = mtree_from_kvs(path, old_kvs); 169 } else { # Add entry plus defaults 170 delete old_kvs; 171 merge_kvs(old_kvs, defaults); 172 merge_kvs(old_kvs, new_kvs); 173 tree[path] = mtree_from_kvs(path, old_kvs); 174 } 175} 176 177BEGIN { 178 nv = "___NO__VALUE___"; 179 180 while ((getline < "/dev/stdin") > 0) { 181 if ($1 ~ "^#") 182 continue; 183 if ($1 == "/set") { 184 for (i = 2; i <= NF; i++) { 185 kv($i); 186 defaults[kv_key] = kv_value; 187 } 188 } else if ($1 == "/unset") { 189 for (i = 2; i <= NF; i++) { 190 kv($i); 191 delete defaults[kv_key]; 192 } 193 } else 194 process_line($1, $0); 195 } 196 197 # Print the last set of defaults. This will carry 198 # over, I think, to makefs' defaults 199 print mtree_from_kvs("/set", defaults) 200 for (x in tree) 201 print tree[x]; 202} 203