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