github.com/ethanhsieh/snapd@v0.0.0-20210615102523-3db9b8e4edc5/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 "os" 26 "path/filepath" 27 "strconv" 28 29 "github.com/snapcore/snapd/dirs" 30 "github.com/snapcore/snapd/osutil" 31 "github.com/snapcore/snapd/overlord/configstate/config" 32 "github.com/snapcore/snapd/systemd" 33 ) 34 35 // see https://www.kernel.org/doc/Documentation/sysctl/kernel.txt 36 // The idea is that options of the form system.kernel. should 37 // match the (/proc/)sys/kernel hierarchy etc. 38 39 func init() { 40 // add supported configuration of this module 41 supportedConfigurations["core.system.kernel.printk.console-loglevel"] = true 42 } 43 44 const ( 45 sysctlConfsDir = "/etc/sysctl.d" 46 snapdSysctlConf = "99-snapd.conf" 47 ) 48 49 // these are the sysctl parameters prefixes we handle 50 var sysctlPrefixes = []string{"kernel.printk"} 51 52 func validateSysctlOptions(tr config.ConfGetter) error { 53 consoleLoglevelStr, err := coreCfg(tr, "system.kernel.printk.console-loglevel") 54 if err != nil { 55 return err 56 } 57 if consoleLoglevelStr != "" { 58 if n, err := strconv.ParseUint(consoleLoglevelStr, 10, 8); err != nil || (n < 0 || n > 7) { 59 return fmt.Errorf("console-loglevel must be a number between 0 and 7, not: %s", consoleLoglevelStr) 60 } 61 } 62 return nil 63 } 64 65 func handleSysctlConfiguration(tr config.ConfGetter, opts *fsOnlyContext) error { 66 root := dirs.GlobalRootDir 67 if opts != nil { 68 root = opts.RootDir 69 } 70 71 consoleLoglevelStr, err := coreCfg(tr, "system.kernel.printk.console-loglevel") 72 if err != nil { 73 return nil 74 } 75 76 content := bytes.NewBuffer(nil) 77 if consoleLoglevelStr != "" { 78 content.WriteString(fmt.Sprintf("kernel.printk = %s 4 1 7\n", consoleLoglevelStr)) 79 } else { 80 // Don't write values to content so that the config 81 // file gets removed and console-loglevel gets reset 82 // to default value from 10-console-messages.conf 83 84 // TODO: this logic will need more non-obvious work to support 85 // kernel parameters that don't have already on-disk defaults. 86 } 87 dirContent := map[string]osutil.FileState{} 88 if content.Len() > 0 { 89 dirContent[snapdSysctlConf] = &osutil.MemoryFileState{ 90 Content: content.Bytes(), 91 Mode: 0644, 92 } 93 } 94 95 dir := filepath.Join(root, sysctlConfsDir) 96 if opts != nil { 97 if err := os.MkdirAll(dir, 0755); err != nil { 98 return err 99 } 100 } 101 102 // write the new config 103 glob := snapdSysctlConf 104 changed, removed, err := osutil.EnsureDirState(dir, glob, dirContent) 105 if err != nil { 106 return err 107 } 108 109 if opts == nil { 110 if len(changed) > 0 || len(removed) > 0 { 111 // apply our configuration or default configuration 112 // via systemd-sysctl for the relevant prefixes 113 return systemd.Sysctl(sysctlPrefixes) 114 } 115 } 116 117 return nil 118 }