github.com/hugh712/snapd@v0.0.0-20200910133618-1a99902bd583/overlord/configstate/configcore/sysctl.go (about) 1 // -*- Mode: Go; indent-tabs-mode: t -*- 2 3 /* 4 * Copyright (C) 2020 Canonical Ltd 5 * 6 * This program is free software: you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License version 3 as 8 * published by the Free Software Foundation. 9 * 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU General Public License for more details. 14 * 15 * You should have received a copy of the GNU General Public License 16 * along with this program. If not, see <http://www.gnu.org/licenses/>. 17 * 18 */ 19 20 package configcore 21 22 import ( 23 "bytes" 24 "fmt" 25 "path/filepath" 26 "strconv" 27 28 "github.com/snapcore/snapd/dirs" 29 "github.com/snapcore/snapd/osutil" 30 "github.com/snapcore/snapd/overlord/configstate/config" 31 "github.com/snapcore/snapd/systemd" 32 ) 33 34 // see https://www.kernel.org/doc/Documentation/sysctl/kernel.txt 35 // The idea is that options of the form system.kernel. should 36 // match the (/proc/)sys/kernel hierarchy etc. 37 38 func init() { 39 // add supported configuration of this module 40 supportedConfigurations["core.system.kernel.printk.console-loglevel"] = true 41 } 42 43 const ( 44 sysctlConfsDir = "/etc/sysctl.d" 45 snapdSysctlConf = "99-snapd.conf" 46 ) 47 48 // these are the sysctl parameters prefixes we handle 49 var sysctlPrefixes = []string{"kernel.printk"} 50 51 func validateSysctlOptions(tr config.ConfGetter) error { 52 consoleLoglevelStr, err := coreCfg(tr, "system.kernel.printk.console-loglevel") 53 if err != nil { 54 return err 55 } 56 if consoleLoglevelStr != "" { 57 if n, err := strconv.ParseUint(consoleLoglevelStr, 10, 8); err != nil || (n < 0 || n > 7) { 58 return fmt.Errorf("console-loglevel must be a number between 0 and 7, not: %s", consoleLoglevelStr) 59 } 60 } 61 return nil 62 } 63 64 func handleSysctlConfiguration(tr config.ConfGetter, opts *fsOnlyContext) error { 65 root := dirs.GlobalRootDir 66 if opts != nil { 67 root = opts.RootDir 68 } 69 70 consoleLoglevelStr, err := coreCfg(tr, "system.kernel.printk.console-loglevel") 71 if err != nil { 72 return nil 73 } 74 75 content := bytes.NewBuffer(nil) 76 if consoleLoglevelStr != "" { 77 content.WriteString(fmt.Sprintf("kernel.printk = %s 4 1 7\n", consoleLoglevelStr)) 78 } else { 79 // Don't write values to content so that the config 80 // file gets removed and console-loglevel gets reset 81 // to default value from 10-console-messages.conf 82 83 // TODO: this logic will need more non-obvious work to support 84 // kernel parameters that don't have already on-disk defaults. 85 } 86 dirContent := map[string]osutil.FileState{} 87 if content.Len() > 0 { 88 dirContent[snapdSysctlConf] = &osutil.MemoryFileState{ 89 Content: content.Bytes(), 90 Mode: 0644, 91 } 92 } 93 94 // write the new config 95 dir := filepath.Join(root, sysctlConfsDir) 96 glob := snapdSysctlConf 97 changed, removed, err := osutil.EnsureDirState(dir, glob, dirContent) 98 if err != nil { 99 return err 100 } 101 102 if opts == nil { 103 if len(changed) > 0 || len(removed) > 0 { 104 // apply our configuration or default configuration 105 // via systemd-sysctl for the relevant prefixes 106 return systemd.Sysctl(sysctlPrefixes) 107 } 108 } 109 110 return nil 111 }