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