load.ha (1663B)
1 // SPDX-License-Identifier: MPL-2.0 2 // (c) Hare authors <https://harelang.org> 3 4 use bufio; 5 use fmt; 6 use io; 7 use memio; 8 use net::ip; 9 use os; 10 use strings; 11 12 let cache_valid = false; 13 let cache: config = config { 14 options = DEFAULT_OPTIONS, 15 ... 16 }; 17 18 @fini fn fini() void = { 19 if (!cache_valid) { 20 return; 21 }; 22 23 strings::freeall(cache.search); 24 free(cache.nameservers); 25 free(cache.sortlist); 26 }; 27 28 // Reads /etc/resolv.conf (or the platform-specific equivalent path) and returns 29 // the configuration therein. If the file does not exist, or is poorly 30 // formatted, returns the default resolver configuration. 31 export fn load() *config = { 32 if (cache_valid) { 33 return &cache; 34 }; 35 36 const file = match (os::open("/etc/resolv.conf")) { 37 case let file: io::file => 38 yield file; 39 case => 40 cache_valid = true; 41 return &cache; 42 }; 43 defer io::close(file)!; 44 45 match (parse(&cache, file)) { 46 case let err: error => 47 fmt::errorfln("Error parsing /etc/resolv.conf: {}", 48 strerror(err)): void; 49 return &cache; 50 case void => 51 cache_valid = true; 52 return &cache; 53 }; 54 }; 55 56 // Parses a resolv.conf-formatted file and populates the given config object. 57 fn parse(conf: *config, in: io::handle) (void | error) = { 58 const rd = read(in); 59 for (const param => next(&rd)!) { 60 switch (param.name) { 61 case "nameserver" => 62 append(conf.nameservers, param.value as ip::addr)!; 63 case "search" => 64 strings::freeall(conf.search); 65 conf.search = strings::dupall(param.value as []str); 66 case "sortlist" => 67 free(conf.sortlist); 68 conf.sortlist = alloc((param.value as []ip::subnet)...)!; 69 case "options" => 70 conf.options = *(param.value as *options); 71 case => void; 72 }; 73 }; 74 };