github.com/stolowski/snapd@v0.0.0-20210407085831-115137ce5a22/osutil/mountprofile_linux.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 osutil 21 22 import ( 23 "bufio" 24 "bytes" 25 "fmt" 26 "io" 27 "os" 28 "strings" 29 ) 30 31 // MountProfile represents an array of mount entries. 32 type MountProfile struct { 33 Entries []MountEntry 34 } 35 36 // LoadMountProfile loads a mount profile from a given file. 37 // 38 // The file may be absent, in such case an empty profile is returned without errors. 39 func LoadMountProfile(fname string) (*MountProfile, error) { 40 f, err := os.Open(fname) 41 if err != nil && os.IsNotExist(err) { 42 return &MountProfile{}, nil 43 } 44 if err != nil { 45 return nil, err 46 } 47 defer f.Close() 48 return ReadMountProfile(f) 49 } 50 51 // LoadMountProfileText loads a mount profile from a given string. 52 func LoadMountProfileText(fstab string) (*MountProfile, error) { 53 return ReadMountProfile(strings.NewReader(fstab)) 54 } 55 56 func SaveMountProfileText(p *MountProfile) (string, error) { 57 var buf bytes.Buffer 58 _, err := p.WriteTo(&buf) 59 if err != nil { 60 return "", err 61 } 62 return buf.String(), nil 63 } 64 65 // Save saves a mount profile (fstab-like) to a given file. 66 // The profile is saved with an atomic write+rename+sync operation. 67 func (p *MountProfile) Save(fname string) error { 68 var buf bytes.Buffer 69 if _, err := p.WriteTo(&buf); err != nil { 70 return err 71 } 72 return AtomicWriteFile(fname, buf.Bytes(), 0644, AtomicWriteFlags(0)) 73 } 74 75 // ReadMountProfile reads and parses a mount profile. 76 // 77 // The supported format is described by fstab(5). 78 func ReadMountProfile(reader io.Reader) (*MountProfile, error) { 79 var p MountProfile 80 scanner := bufio.NewScanner(reader) 81 for scanner.Scan() { 82 s := scanner.Text() 83 s = strings.TrimSpace(s) 84 // Skip lines that only contain a comment, that is, those that start 85 // with the '#' character (ignoring leading spaces). This specifically 86 // allows us to parse '#' inside individual fields, which the fstab(5) 87 // specification allows. 88 if strings.IndexByte(s, '#') == 0 { 89 continue 90 } 91 // Skip lines that are totally empty 92 if s == "" { 93 continue 94 } 95 entry, err := ParseMountEntry(s) 96 if err != nil { 97 return nil, err 98 } 99 p.Entries = append(p.Entries, entry) 100 } 101 if err := scanner.Err(); err != nil { 102 return nil, err 103 } 104 return &p, nil 105 } 106 107 // WriteTo writes a mount profile to the given writer. 108 // 109 // The supported format is described by fstab(5). 110 // Note that there is no support for comments. 111 func (p *MountProfile) WriteTo(writer io.Writer) (int64, error) { 112 var written int64 113 for i := range p.Entries { 114 var n int 115 var err error 116 if n, err = fmt.Fprintf(writer, "%s\n", p.Entries[i]); err != nil { 117 return written, err 118 } 119 written += int64(n) 120 } 121 return written, nil 122 }