parse_fs.include.awk (7289B)
1 BEGIN{ 2 param_validator["source"] = ".+" 3 param_validator["type"] = "[a-z0-9._]+" 4 param_validator["options"] = ".*" 5 param_validator["bundles"] = "[^ ]+" 6 param_validator["down"] = "(umount|readonly|keep)" 7 param_validator["mkdir"] = "(true|false)" 8 param_validator["premounted"] = "(true|false)" 9 param_validator["service_name"] = "[^ /]+" 10 param_validator["dependencies"] = "[^/]*" 11 param_validator["extra_dependencies"] = "[^/]+" 12 fail = 0 13 } 14 15 #function q(s) { # quote string for execline 16 # gsub(/\\/, "\\\\", s) 17 # gsub(/\n/, "\\n", s) 18 # gsub(/\"/, "\\\"", s) 19 # return "\"" s "\"" 20 #} 21 22 function fatal_mtp(s){ 23 print mountpoints[mtp] ": Error: " s " [" mtp "]" >"/dev/stderr" 24 fail=1 25 exit 1 26 } 27 28 function fatal_parse(s){ 29 print FILENAME ":" FNR ": Error: " s >"/dev/stderr" 30 fail=1 31 exit 1 32 } 33 34 function dbg(s){ 35 if(debug) { 36 print("#" s) 37 } 38 } 39 40 function is_parent(child_path, parent_path) { 41 if(child_path == "/") { 42 return 0 43 } 44 if(parent_path == "/") { 45 return 1 46 } 47 parent_path = parent_path "/" 48 return substr(child_path, 1, length(parent_path)) == parent_path 49 } 50 # function is_parent(child_path, parent_path, result) { 51 # result = is_parent_(child_path, parent_path) 52 # dbg("++ '" parent_path "' " (result?"is":"is NOT") " parent of '" child_path "'") 53 # return result 54 # } 55 56 function mtp_get(mtp_x, name) { 57 if(!((mtp_x,name) in params)) { 58 fatal_mtp("parameter '" name "' not set") 59 } 60 if(name in param_validator) { 61 if(params[mtp_x,name] !~ ("^" param_validator[name] "$")) { 62 fatal_mtp("Internal: parameter '" mtp_x "','" name "' set to unrecognized value '" params[mtp_x,name] "'") 63 } 64 } else if (!(name in param_extras)) { 65 fatal_mtp("Internal: parameter name '" mtp_x "','" name "' not known") 66 } 67 return params[mtp_x,name] 68 } 69 70 function get(name) { 71 return mtp_get(mtp, name) 72 } 73 74 # execline quoted get function 75 function qget(name) { 76 if(name == "") { 77 return q(mtp) 78 } 79 if(name == "remount_options") { 80 return get("options") == "defaults" ? "remount" : q("remount," get("options")) 81 } 82 return q(get(name)) 83 } 84 85 function set(name, value) { 86 if(name in param_validator) { 87 if(value !~ ("^" param_validator[name] "$")) { 88 fatal_mtp("Internal: tried to set '" name "' set to unrecognized value '" value "'") 89 } 90 } else if (!(name in param_extras)) { 91 fatal_mtp("Internal: parameter name '" name "' not known") 92 } 93 params[mtp,name] = value 94 } 95 96 function set1(name, value) { 97 if((mtp,name) in params) { 98 fatal_mtp("parameter '" name "' already set to '" params[mtp,value] "', tried to assign '" value "'") 99 } 100 set(name, value) 101 } 102 103 function boolean(name) { # Check boolean parameter 104 return get(name) == "true" 105 } 106 107 function down(is_value) { # Check "down" parameter 108 return is_value == get("down") 109 } 110 111 function down_umount() { return down("umount") } 112 function down_keep() { return down("keep") } 113 function down_readonly() { return down("readonly") } 114 115 function dependencies( s, i) { 116 s = "" 117 for(i=1; i<=dn; i++) { 118 s = s "\t" ds[i] "\n" 119 } 120 return s 121 } 122 123 function find_topmost_mount( found, mtp2) { 124 found = "" 125 for(mtp2 in mountpoints) { 126 if(length(mtp2) > length(found) && is_parent(mtp, mtp2)) { 127 found = mtp2 128 } 129 } 130 if(!length(found)) { 131 # consider if this should be error for mtp != "/" 132 return "" 133 } 134 dbg(" dep FOUND: '" found "' -> svc: '" mtp_get(found, "service_name") "'") 135 if(!boolean("mkdir")) { 136 if(mtp_get(found,"premounted") == "true" && mtp_get(found,"down") != "umount") { 137 # Dependency would be superfluous 138 return "" 139 } 140 } 141 # fatal_mtp("FOUND: '" found "' -> svc: '" mtp_get(found, "service_name") "'") 142 return params[found, "service_name"] 143 } 144 145 function process_record( name, i, mtp2) { 146 dbg("## ----------------------------------------------------------------------") 147 if(!((mtp,"premounted") in params)) { 148 set1("premounted", "false") 149 } 150 151 if(!((mtp,"mkdir") in params)) { 152 set1("mkdir", boolean("premounted") ? "false" : "true") 153 } 154 155 if(!((mtp,"down") in params)) { 156 set1("down", "umount") 157 } 158 159 if(!((mtp,"options") in params)) { 160 set1("options", "rw") 161 } 162 163 # set1("dependencies", "foo bar") 164 if(((mtp,"dependencies") in params)) { 165 if(((mtp,"extra_dependencies") in params)) { 166 fatal_mtp("Define either 'extra_dependencies' or 'dependencies', not both") 167 } 168 dn = split(get("dependencies"), ds) 169 170 } else { 171 if(((mtp,"extra_dependencies") in params)) { 172 dn = split(get("extra_dependencies"), ds) 173 } else { 174 dn = 0 175 } 176 i = find_topmost_mount() 177 if(length(i)) { 178 dn += 1 179 ds[dn] = i 180 } 181 182 } 183 184 #print(">>> " mtp " <<< " ((mtp,"service_name") in params)) 185 # if(!((mtp,"service_name") in params)) { 186 # It may be initialized by access from find_topmost_mount() 187 if(length(params[mtp,"service_name"]) == 0) { 188 if(mtp == "/") { 189 if(!boolean("premounted")) { 190 fatal_mtp("rootfs not set as premounted") 191 } 192 set("service_name", "rootfs") 193 } else { 194 svc_name = mtp 195 gsub("/", "-", svc_name) 196 set("service_name", "mount" svc_name) 197 } 198 } 199 svc_name = get("service_name") 200 if(svc_name !~ ("^" param_validator["service_name"] "$")) { 201 fatal_mtp("Service name '" svc_name "' not valid") 202 } 203 if(svc_name in services) { 204 fatal_mtp("Service name '" svc_name "' collides with mountpoint '" services[svc_name] "' defined at " mountpoints[services[svc_name]]) 205 } 206 services[svc_name] = mtp 207 208 if(debug) { 209 printf("#>> mtp='%s'\n", mtp) 210 for(name in params) { 211 if(substr(name, 1, length(mtp)+1) == mtp SUBSEP) { 212 printf("#>> %s='%s'\n", substr(name, length(mtp)+1), params[name]) 213 } 214 } 215 } 216 217 write_oneshot() 218 219 if((mtp,"bundles") in params) { 220 split(get("bundles"), bundle_list) 221 for(i in bundle_list) { 222 add_to_bundle(bundle_list[i], svc_name) 223 } 224 delete bundle_list 225 } 226 227 #delete params 228 mtp = "" 229 } 230 231 function process_bundles( name) { 232 for(name in bundles) { 233 write_bundle(name) 234 } 235 } 236 237 function validate_mountpoint( mtp2) { 238 if(mtp in mountpoints) { 239 fatal_parse("duplicate definition of mountpoint '" $0 "', previous definition at " mountpoints[$0]) 240 } 241 if(mtp != "/" && mtp ~ "/$") { 242 fatal_parse("Trailing slash not allowed: '" mtp "'") 243 } 244 if(mtp ~ "/(|\\.|\\.\\.)/") { 245 fatal_parse("Mountpoint '" mtp "' is not canonical absolute path") 246 } 247 for(mtp2 in mountpoints) { 248 if(is_parent(mtp2, mtp)) { 249 fatal_parse("mountpoint '" mtp "' defined after implicit reverse dependency '" mtp2 "' located at " mountpoints[mtp2]) 250 } 251 } 252 } 253 254 # Skip comments 255 /^[ \t]*#/{ next } 256 257 # mountpoint (aka fs_file in fstab) 258 /^\//{ 259 if(mtp) { 260 process_record() 261 } 262 mtp=$0 263 validate_mountpoint() 264 mountpoints[mtp] = FILENAME ":" FNR 265 next 266 } 267 268 # All other lines 269 { 270 line=$0 271 m = match(line, /^[ \t]+/) 272 if(m) { 273 # Strip leading whitespace 274 line = substr(line, m+RLENGTH) 275 } 276 if(length(line) == 0) { 277 # Skip empty lines 278 next 279 } 280 m = match(line, /=/) 281 if(m) { 282 name = substr(line, 1, m-1) 283 value = substr(line, m+RLENGTH) 284 if((mtp, name) in params) { 285 fatal_parse("Duplicate definition of parameter '" name "'") 286 } 287 if(!(name in param_validator)) { 288 fatal_parse("Unrecognized parameter '" name "'") 289 } 290 if(value !~ ("^" param_validator[name] "$")) { 291 fatal_parse("Invalid value for parameter '" name "': '" value "'") 292 } 293 params[mtp,name] = value 294 } else { 295 fatal_parse("missing '=' in parameter definition") 296 } 297 } 298 299 END{ 300 if(fail) { 301 exit fail 302 } 303 if(mtp) { 304 process_record() 305 } 306 print_bundles() 307 }