1#!/usr/bin/awk -f 2 3# 4# Copyright (c) 2015 M. Warner Losh. 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# $FreeBSD$ 28# 29 30# 31# Takes a meta-log created by installworld and friends, plus 32# additions from NanoBSD to augment its build to communicate when 33# files move around after installworld / installkernel phase of 34# NanoBSD. 35# 36# All mtree lines from the metafile have a path, followed by 37# a number of keywords. 38# 39# This script recognizes the following new keywords 40# 41# unlink[=x] remove the path from the output. 42# copy_from=x create new entry for path copied from 43# the keywords from x. 44# move_from=x create new entry for path copied from 45# the keywords from x. Remove path from 46# the output. 47# 48# In addition, when path matches a previous entry, the 49# new entry and previous entry are merged. 50# 51# Special note: when uid and uname are both present, 52# uid is ignored. Ditto gid/gname. 53# 54# Also, the paths above have to match exactly, so X 55# should start with "./". 56# 57 58function die(str) 59{ 60 print str > "/dev/stderr"; 61 exit 1; 62} 63 64function kv(str) 65{ 66 if (split(str, xxx, "=") == 2) { 67 kv_key = xxx[1]; 68 kv_value = xxx[2]; 69 } else { 70 kv_key = str; 71 kv_value = nv; 72 } 73} 74 75# Output the mtree for path based on the kvs. 76function mtree_from_kvs(path, kvs) 77{ 78 lv = path " "; 79 for (k in kvs) { 80 if (kvs[k] == nv) 81 lv = lv k " "; 82 else 83 lv = lv k "=" kvs[k] " "; 84 } 85 return lv; 86} 87 88# Parse the mtree line into path + KVs. Use a sentinal value 89# for a bare keyword, which is extremely unlikely to be used 90# for real. 91function line2kv(kvs, str) 92{ 93 delete kvs; 94 95 n = split(str, yyy, " "); 96 for (i = 2; i <= n; i++) { 97 s = yyy[i]; 98 if (split(s, xxx, "=") == 2) 99 kvs[xxx[1]] = xxx[2]; 100 else 101 kvs[s] = nv; 102 } 103} 104 105 106# old += new 107function merge_kvs(old, new) 108{ 109 for (k in new) { 110 # uname / uid -- last one wins. 111 if (k == "uid" && "uname" in old) 112 delete old["uname"] 113 if (k == "uname" && "uid" in old) 114 delete old["uid"]; 115 # gname / gid -- last one wins. 116 if (k == "gid" && "gname" in old) 117 delete old["gname"] 118 if (k == "gname" && "gid" in old) 119 delete old["gid"]; 120 # Otherwise newest value wins 121 old[k] = new[k]; 122 } 123} 124 125# Process the line we've read in, per the comments below 126function process_line(path, new) 127{ 128 # Clear kvs 129 line2kv(new_kvs, new); 130 131 if ("unlink" in new_kvs) { 132 # A file removed 133 # Sanity check to see if tree[path] exists? 134 # Makes sure when foo/bar/baz exists and foo/bar 135 # unlinked, baz is gone (for all baz). 136 if (path !~ "^\./") 137 die("bad path in : " new); 138 delete tree[path]; # unlink 139 return; 140 # } else if (new_kvs["append_from"]) { # not implemented 141 } else if ("copy_from" in new_kvs) { 142 # A file copied from another location, preserve its 143 # attribute for new file. 144 # Also merge any new attributes from this line. 145 from = new_kvs["copy_from"]; 146 if (from !~ "^\./") 147 die("bad path in : " new); 148 delete new_kvs["copy_from"]; 149 line2kv(old_kvs, tree[from]); # old_kvs = kv's in entry 150 merge_kvs(old_kvs, new_kvs); # old_kvs += new_kvs 151 tree[path] = mtree_from_kvs(path, old_kvs); 152 } else if ("move_from" in new_kvs) { 153 # A file moved from another location, preserve its 154 # attribute for new file, and scrag old location 155 # Also merge any new attributes from this line. 156 from = new_kvs["move_from"]; 157 if (from !~ "^\./") 158 die("bad path in : " new); 159 delete new_kvs["move_from"]; 160 line2kv(old_kvs, tree[from]); # old_kvs = kv's in entry 161 merge_kvs(old_kvs, new_kvs); # old_kvs += new_kvs 162 tree[path] = mtree_from_kvs(path, old_kvs); 163 delete tree[from]; # unlink 164 } else if (tree[path]) { # Update existing entry with new line 165 line2kv(old_kvs, tree[path]); # old_kvs = kv's in entry 166 merge_kvs(old_kvs, new_kvs); # old_kvs += new_kvs 167 tree[path] = mtree_from_kvs(path, old_kvs); 168 } else { # Add entry plus defaults 169 delete old_kvs; 170 merge_kvs(old_kvs, defaults); 171 merge_kvs(old_kvs, new_kvs); 172 tree[path] = mtree_from_kvs(path, old_kvs); 173 } 174} 175 176BEGIN { 177 nv = "___NO__VALUE___"; 178 179 while ((getline < "/dev/stdin") > 0) { 180 if ($1 ~ "^#") 181 continue; 182 if ($1 == "/set") { 183 for (i = 2; i <= NF; i++) { 184 kv($i); 185 defaults[kv_key] = kv_value; 186 } 187 } else if ($1 == "/unset") { 188 for (i = 2; i <= NF; i++) { 189 kv($i); 190 delete defaults[kv_key]; 191 } 192 } else 193 process_line($1, $0); 194 } 195 196 # Print the last set of defaults. This will carry 197 # over, I think, to makefs' defaults 198 print mtree_from_kvs("/set", defaults) 199 for (x in tree) 200 print tree[x]; 201} 202