1-- 2-- Copyright (c) 2015 Pedro Souza <pedrosouza@freebsd.org> 3-- All rights reserved. 4-- 5-- Redistribution and use in source and binary forms, with or without 6-- modification, are permitted provided that the following conditions 7-- are met: 8-- 1. Redistributions of source code must retain the above copyright 9-- notice, this list of conditions and the following disclaimer. 10-- 2. Redistributions in binary form must reproduce the above copyright 11-- notice, this list of conditions and the following disclaimer in the 12-- documentation and/or other materials provided with the distribution. 13-- 14-- THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15-- ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16-- IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17-- ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18-- FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19-- DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20-- OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21-- HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22-- LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23-- OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24-- SUCH DAMAGE. 25-- 26-- $FreeBSD$ 27-- 28 29local config = {}; 30 31local modules = {}; 32 33function config.setKey(k, n, v) 34 if modules[k] == nil then 35 modules[k] = {}; 36 end 37 modules[k][n] = v; 38end 39 40local pattern_table = { 41 [1] = { 42 str = "^%s*(#.*)", 43 process = function(k, v) end 44 }, 45 -- module_load="value" 46 [2] = { 47 str = "^%s*([%w_]+)_load%s*=%s*\"([%w%s%p]-)\"%s*(.*)", 48 process = function(k, v) 49 if modules[k] == nil then 50 modules[k] = {}; 51 end 52 modules[k].load = string.upper(v); 53 end 54 }, 55 -- module_name="value" 56 [3] = { 57 str = "^%s*([%w_]+)_name%s*=%s*\"([%w%s%p]-)\"%s*(.*)", 58 process = function(k, v) 59 config.setKey(k, "name", v); 60 end 61 }, 62 -- module_type="value" 63 [4] = { 64 str = "^%s*([%w_]+)_type%s*=%s*\"([%w%s%p]-)\"%s*(.*)", 65 process = function(k, v) 66 config.setKey(k, "type", v); 67 end 68 }, 69 -- module_flags="value" 70 [5] = { 71 str = "^%s*([%w_]+)_flags%s*=%s*\"([%w%s%p]-)\"%s*(.*)", 72 process = function(k, v) 73 config.setKey(k, "flags", v); 74 end 75 }, 76 -- module_before="value" 77 [6] = { 78 str = "^%s*([%w_]+)_before%s*=%s*\"([%w%s%p]-)\"%s*(.*)", 79 process = function(k, v) 80 config.setKey(k, "before", v); 81 end 82 }, 83 -- module_after="value" 84 [7] = { 85 str = "^%s*([%w_]+)_after%s*=%s*\"([%w%s%p]-)\"%s*(.*)", 86 process = function(k, v) 87 config.setKey(k, "after", v); 88 end 89 }, 90 -- module_error="value" 91 [8] = { 92 str = "^%s*([%w_]+)_error%s*=%s*\"([%w%s%p]-)\"%s*(.*)", 93 process = function(k, v) 94 config.setKey(k, "error", v); 95 end 96 }, 97 -- exec="command" 98 [9] = { 99 str = "^%s*exec%s*=%s*\"([%w%s%p]-)\"%s*(.*)", 100 process = function(k, v) 101 if loader.perform(k) ~= 0 then 102 print("Failed to exec '"..k.."'"); 103 end 104 end 105 }, 106 -- env_var="value" 107 [10] = { 108 str = "^%s*([%w%p]+)%s*=%s*\"([%w%s%p]-)\"%s*(.*)", 109 process = function(k, v) 110 if loader.setenv(k, v) ~= 0 then 111 print("Failed to set '"..k.."' with value: "..v..""); 112 end 113 end 114 }, 115 -- env_var=num 116 [11] = { 117 str = "^%s*([%w%p]+)%s*=%s*(%d+)%s*(.*)", 118 process = function(k, v) 119 if loader.setenv(k, v) ~= 0 then 120 print("Failed to set '"..k.."' with value: "..v..""); 121 end 122 end 123 } 124}; 125 126function config.isValidComment(c) 127 if c ~= nil then 128 local s = string.match(c, "^%s*#.*"); 129 if s == nil then 130 s = string.match(c, "^%s*$"); 131 end 132 if s == nil then 133 return false; 134 end 135 end 136 return true; 137end 138 139function config.loadmod(mod, silent) 140 local status = true; 141 for k, v in pairs(mod) do 142 if v.load == "YES" then 143 local str = "load "; 144 if v.flags ~= nil then 145 str = str .. v.flags .. " "; 146 end 147 if v.type ~= nil then 148 str = str .. "-t " .. v.type .. " "; 149 end 150 if v.name ~= nil then 151 str = str .. v.name; 152 else 153 str = str .. k; 154 end 155 156 if v.before ~= nil then 157 if loader.perform(v.before) ~= 0 then 158 if not silent then 159 print("Failed to execute '"..v.before.."' before loading '"..k.."'"); 160 end 161 status = false; 162 end 163 end 164 165 if loader.perform(str) ~= 0 then 166 if not silent then 167 print("Failed to execute '" .. str .. "'"); 168 end 169 if v.error ~= nil then 170 loader.perform(v.error); 171 end 172 status = false; 173 end 174 175 if v.after ~= nil then 176 if loader.perform(v.after) ~= 0 then 177 if not silent then 178 print("Failed to execute '"..v.after.."' after loading '"..k.."'"); 179 end 180 status = false; 181 end 182 end 183 184 else 185 --if not silent then print("Skiping module '".. k .. "'"); end 186 end 187 end 188 189 return status; 190end 191 192function config.parse(name, silent) 193 local f = io.open(name); 194 if f == nil then 195 if not silent then 196 print("Failed to open config: '" .. name.."'"); 197 end 198 return false; 199 end 200 201 local text; 202 local r; 203 204 text, r = io.read(f); 205 206 if text == nil then 207 if not silent then 208 print("Failed to read config: '" .. name.."'"); 209 end 210 return false; 211 end 212 213 local n = 1; 214 local status = true; 215 216 for line in string.gmatch(text, "([^\n]+)") do 217 218 if string.match(line, "^%s*$") == nil then 219 local found = false; 220 221 for i, val in ipairs(pattern_table) do 222 local k, v, c = string.match(line, val.str); 223 if k ~= nil then 224 found = true; 225 226 if config.isValidComment(c) then 227 val.process(k, v); 228 else 229 print("Malformed line ("..n.."):\n\t'"..line.."'"); 230 status = false; 231 end 232 233 break; 234 end 235 end 236 237 if found == false then 238 print("Malformed line ("..n.."):\n\t'"..line.."'"); 239 status = false; 240 end 241 end 242 n = n + 1; 243 end 244 245 return status; 246end 247 248function config.loadkernel() 249 local flags = loader.getenv("kernel_options") or ""; 250 local kernel = loader.getenv("kernel"); 251 252 local try_load = function (names) 253 for name in names:gmatch("([^;]+)%s*;?") do 254 r = loader.perform("load "..flags.." "..name); 255 if r == 0 then 256 return name; 257 end 258 end 259 return nil; 260 end; 261 262 local load_bootfile = function() 263 local bootfile = loader.getenv("bootfile"); 264 265 -- append default kernel name 266 if not bootfile then 267 bootfile = "kernel"; 268 else 269 bootfile = bootfile..";kernel"; 270 end 271 272 return try_load(bootfile); 273 end; 274 275 -- kernel not set, try load from default module_path 276 if kernel == nil then 277 local res = load_bootfile(); 278 279 if res ~= nil then 280 return true; 281 else 282 print("Failed to load kernel '"..res.."'"); 283 return false; 284 end 285 else 286 local module_path = loader.getenv("module_path"); 287 local res = nil; 288 289 -- first try load kernel with module_path = /boot/${kernel} 290 -- then try load with module_path=${kernel} 291 local paths = {"/boot/"..kernel, kernel}; 292 293 for k,v in pairs(paths) do 294 295 loader.setenv("module_path", v); 296 res = load_bootfile(); 297 298 -- succeeded add path to module_path 299 if res ~= nil then 300 loader.setenv("module_path", v..";"..module_path); 301 return true; 302 end 303 end 304 305 -- failed to load with ${kernel} as a directory 306 -- try as a file 307 res = try_load(kernel); 308 if res ~= nil then 309 return true; 310 else 311 print("Failed to load kernel '"..res.."'"); 312 return false; 313 end 314 end 315end 316 317 318function config.load(file) 319 320 if not file then 321 file = "/boot/defaults/loader.conf"; 322 end 323 324 if not config.parse(file) then 325-- print("Failed to parse configuration: '"..file.."'"); 326 end 327 328 local f = loader.getenv("loader_conf_files"); 329 if f ~= nil then 330 for name in string.gmatch(f, "([%w%p]+)%s*") do 331 if not config.parse(name) then 332-- print("Failed to parse configuration: '"..name.."'"); 333 end 334 end 335 end 336 337 print("Loading kernel..."); 338 config.loadkernel(); 339 340 print("Loading configurations..."); 341 if not config.loadmod(modules) then 342 print("Could not load configurations!"); 343 end 344end 345 346function config.reload(kernel) 347 local res = 1; 348 349 -- unload all modules 350 print("Unloading modules..."); 351 loader.perform("unload"); 352 353 if kernel ~= nil then 354 res = loader.perform("load "..kernel); 355 if res == 0 then 356 print("Kernel '"..kernel.."' loaded!"); 357 end 358 end 359 360 -- failed to load kernel or it is nil 361 -- then load default 362 if res == 1 then 363 print("Loading default kernel..."); 364 config.loadkernel(); 365 end 366 367 -- load modules 368 config.loadmod(modules); 369end 370 371return config 372