mrrl-system-config

system configuration on top of MRRL
git clone https://ccx.te2000.cz/git/mrrl-system-config
Log | Files | Refs

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 }