github.com/david-imola/snapd@v0.0.0-20210611180407-2de8ddeece6d/overlord/configstate/configcore/picfg.go (about) 1 // -*- Mode: Go; indent-tabs-mode: t -*- 2 3 /* 4 * Copyright (C) 2017 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 "fmt" 24 "os" 25 "path/filepath" 26 "strings" 27 28 "github.com/snapcore/snapd/boot" 29 "github.com/snapcore/snapd/dirs" 30 "github.com/snapcore/snapd/logger" 31 "github.com/snapcore/snapd/osutil" 32 "github.com/snapcore/snapd/overlord/configstate/config" 33 ) 34 35 // valid pi config keys 36 var piConfigKeys = map[string]bool{ 37 "disable_overscan": true, 38 "force_turbo": true, 39 "framebuffer_width": true, 40 "framebuffer_height": true, 41 "framebuffer_depth": true, 42 "framebuffer_ignore_alpha": true, 43 "overscan_left": true, 44 "overscan_right": true, 45 "overscan_top": true, 46 "overscan_bottom": true, 47 "overscan_scale": true, 48 "display_rotate": true, 49 "hdmi_cvt": true, 50 "hdmi_group": true, 51 "hdmi_mode": true, 52 "hdmi_timings": true, 53 "hdmi_drive": true, 54 "avoid_warnings": true, 55 "gpu_mem_256": true, 56 "gpu_mem_512": true, 57 "gpu_mem": true, 58 "sdtv_aspect": true, 59 "config_hdmi_boost": true, 60 "hdmi_force_hotplug": true, 61 "start_x": true, 62 } 63 64 func init() { 65 // add supported config keys 66 for k := range piConfigKeys { 67 s := fmt.Sprintf("core.pi-config.%s", strings.Replace(k, "_", "-", -1)) 68 supportedConfigurations[s] = true 69 } 70 } 71 72 func updatePiConfig(path string, config map[string]string) error { 73 f, err := os.Open(path) 74 if err != nil { 75 return err 76 } 77 defer f.Close() 78 79 toWrite, err := updateKeyValueStream(f, piConfigKeys, config) 80 if err != nil { 81 return err 82 } 83 84 if toWrite != nil { 85 s := strings.Join(toWrite, "\n") 86 // ensure we have a final newline in the file 87 s += "\n" 88 return osutil.AtomicWriteFile(path, []byte(s), 0644, 0) 89 } 90 91 return nil 92 } 93 94 var ( 95 errPiConfigNotSupported = fmt.Errorf("configuring pi-config not supported in current mode") 96 ) 97 98 func piConfigFile(opts *fsOnlyContext) (string, error) { 99 rootDir := dirs.GlobalRootDir 100 subdir := "/boot/uboot" 101 if opts != nil { 102 rootDir = opts.RootDir 103 } else { 104 // not a filesystem only apply, so we may be operating on a run system 105 // on UC20, in which case we shouldn't use the /boot/uboot/ option and 106 // instead should use /run/mnt/ubuntu-seed/ 107 mode, _, _ := boot.ModeAndRecoverySystemFromKernelCommandLine() 108 switch mode { 109 case boot.ModeRun: 110 rootDir = boot.InitramfsUbuntuSeedDir 111 subdir = "" 112 case boot.ModeInstall, boot.ModeRecover: 113 // we don't support configuring pi-config in these modes as it is 114 // unclear what the right behavior is 115 return "", errPiConfigNotSupported 116 } 117 } 118 return filepath.Join(rootDir, subdir, "config.txt"), nil 119 } 120 121 func handlePiConfiguration(tr config.ConfGetter, opts *fsOnlyContext) error { 122 configFile, err := piConfigFile(opts) 123 if err != nil && err != errPiConfigNotSupported { 124 return err 125 } 126 if err == errPiConfigNotSupported { 127 logger.Debugf("ignoring pi-config settings mode where pi-config changes are unsupported") 128 return nil 129 } 130 if osutil.FileExists(configFile) { 131 // snapctl can actually give us the whole dict in 132 // JSON, in a single call; use that instead of this. 133 config := map[string]string{} 134 for key := range piConfigKeys { 135 output, err := coreCfg(tr, fmt.Sprintf("pi-config.%s", strings.Replace(key, "_", "-", -1))) 136 if err != nil { 137 return err 138 } 139 config[key] = output 140 } 141 if err := updatePiConfig(configFile, config); err != nil { 142 return err 143 } 144 } 145 return nil 146 }