github.com/stolowski/snapd@v0.0.0-20210407085831-115137ce5a22/osutil/mountentry_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 "fmt" 24 "strconv" 25 "strings" 26 "syscall" 27 ) 28 29 // ParseMountEntry parses a fstab-like entry. 30 func ParseMountEntry(s string) (MountEntry, error) { 31 var e MountEntry 32 var err error 33 var df, cpn int 34 fields := strings.FieldsFunc(s, func(r rune) bool { return r == ' ' || r == '\t' }) 35 // Look for any inline comments. The first field that starts with '#' is a comment. 36 for i, field := range fields { 37 if strings.HasPrefix(field, "#") { 38 fields = fields[:i] 39 break 40 } 41 } 42 // Do all error checks before any assignments to `e' 43 if len(fields) < 3 || len(fields) > 6 { 44 return e, fmt.Errorf("expected between 3 and 6 fields, found %d", len(fields)) 45 } 46 e.Name = unescape(fields[0]) 47 e.Dir = unescape(fields[1]) 48 e.Type = unescape(fields[2]) 49 // Parse Options if we have at least 4 fields 50 if len(fields) > 3 { 51 e.Options = strings.Split(unescape(fields[3]), ",") 52 } 53 // Parse DumpFrequency if we have at least 5 fields 54 if len(fields) > 4 { 55 df, err = strconv.Atoi(fields[4]) 56 if err != nil { 57 return e, fmt.Errorf("cannot parse dump frequency: %q", fields[4]) 58 } 59 } 60 e.DumpFrequency = df 61 // Parse CheckPassNumber if we have at least 6 fields 62 if len(fields) > 5 { 63 cpn, err = strconv.Atoi(fields[5]) 64 if err != nil { 65 return e, fmt.Errorf("cannot parse check pass number: %q", fields[5]) 66 } 67 } 68 e.CheckPassNumber = cpn 69 return e, nil 70 } 71 72 // MountOptsToCommonFlags converts mount options strings to a mount flag, 73 // returning unparsed flags. The unparsed flags will not contain any snapd- 74 // specific mount option, those starting with the string "x-snapd." 75 func MountOptsToCommonFlags(opts []string) (flags int, unparsed []string) { 76 for _, opt := range opts { 77 switch opt { 78 case "rw": 79 // There's no flag for rw 80 case "ro": 81 flags |= syscall.MS_RDONLY 82 case "nosuid": 83 flags |= syscall.MS_NOSUID 84 case "nodev": 85 flags |= syscall.MS_NODEV 86 case "noexec": 87 flags |= syscall.MS_NOEXEC 88 case "sync": 89 flags |= syscall.MS_SYNCHRONOUS 90 case "remount": 91 flags |= syscall.MS_REMOUNT 92 case "mand": 93 flags |= syscall.MS_MANDLOCK 94 case "dirsync": 95 flags |= syscall.MS_DIRSYNC 96 case "noatime": 97 flags |= syscall.MS_NOATIME 98 case "nodiratime": 99 flags |= syscall.MS_NODIRATIME 100 case "bind": 101 flags |= syscall.MS_BIND 102 case "rbind": 103 flags |= syscall.MS_BIND | syscall.MS_REC 104 case "move": 105 flags |= syscall.MS_MOVE 106 case "silent": 107 flags |= syscall.MS_SILENT 108 case "acl": 109 flags |= syscall.MS_POSIXACL 110 case "private": 111 flags |= syscall.MS_PRIVATE 112 case "rprivate": 113 flags |= syscall.MS_PRIVATE | syscall.MS_REC 114 case "slave": 115 flags |= syscall.MS_SLAVE 116 case "rslave": 117 flags |= syscall.MS_SLAVE | syscall.MS_REC 118 case "shared": 119 flags |= syscall.MS_SHARED 120 case "rshared": 121 flags |= syscall.MS_SHARED | syscall.MS_REC 122 case "relatime": 123 flags |= syscall.MS_RELATIME 124 case "strictatime": 125 flags |= syscall.MS_STRICTATIME 126 default: 127 if !strings.HasPrefix(opt, "x-snapd.") { 128 unparsed = append(unparsed, opt) 129 } 130 } 131 } 132 return flags, unparsed 133 } 134 135 // MountOptsToFlags converts mount options strings to a mount flag. 136 func MountOptsToFlags(opts []string) (flags int, err error) { 137 flags, unparsed := MountOptsToCommonFlags(opts) 138 for _, opt := range unparsed { 139 if !strings.HasPrefix(opt, "x-snapd.") { 140 return 0, fmt.Errorf("unsupported mount option: %q", opt) 141 } 142 } 143 return flags, nil 144 }