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