]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - tools/tools/nanobsd/mtree-dedup.awk
MFV r328225: 8603 rename zilog's "zl_writer_lock" to "zl_issuer_lock"
[FreeBSD/FreeBSD.git] / tools / tools / nanobsd / mtree-dedup.awk
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
59 function die(str)
60 {
61         print str > "/dev/stderr";
62         exit 1;
63 }
64
65 function 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.
77 function 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.
92 function 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
108 function 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
127 function 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
177 BEGIN {
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 }