pax_global_header00006660000000000000000000000064124400767600014520gustar00rootroot0000000000000052 comment=eb4090f26517e619566a715761f32d9c281754b1 golang-github-d-tux-go-fstab-0.0.0+git.2014.12.04.eb4090f265/000077500000000000000000000000001244007676000221175ustar00rootroot00000000000000golang-github-d-tux-go-fstab-0.0.0+git.2014.12.04.eb4090f265/.gitignore000066400000000000000000000004031244007676000241040ustar00rootroot00000000000000# Compiled Object files, Static and Dynamic libs (Shared Objects) *.o *.a *.so # Folders _obj _test # Architecture specific extensions/prefixes *.[568vq] [568vq].out *.cgo1.go *.cgo2.c _cgo_defun.c _cgo_gotypes.go _cgo_export.* _testmain.go *.exe *.test golang-github-d-tux-go-fstab-0.0.0+git.2014.12.04.eb4090f265/.travis.yml000066400000000000000000000000141244007676000242230ustar00rootroot00000000000000language: gogolang-github-d-tux-go-fstab-0.0.0+git.2014.12.04.eb4090f265/LICENSE000066400000000000000000000027171244007676000231330ustar00rootroot00000000000000Copyright (c) 2014, deniswernert All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of the {organization} nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.golang-github-d-tux-go-fstab-0.0.0+git.2014.12.04.eb4090f265/README.md000066400000000000000000000002551244007676000234000ustar00rootroot00000000000000go-fstab ======== [![Build Status](https://travis-ci.org/deniswernert/go-fstab.svg?branch=master)](https://travis-ci.org/deniswernert/go-fstab) Simple fstab parser for Go golang-github-d-tux-go-fstab-0.0.0+git.2014.12.04.eb4090f265/fstab.go000066400000000000000000000030501244007676000235430ustar00rootroot00000000000000// Package fstab parses and serializes linux filesystem mounts information package fstab import ( "bufio" "fmt" "io" "os" ) type Mounts []*Mount // String serializes a list of mounts to the fstab format func (mounts Mounts) String() (output string) { for i, mount := range mounts { if i > 0 { output += "\n" } output += mount.String() } return } // PaddedString serializes a list of mounts to the fstab format with padding. func (mounts Mounts) PaddedString(paddings ...int) (output string) { for i, mount := range mounts { if i > 0 { output += "\n" } output += mount.PaddedString(paddings...) } return } // ParseSystem parses your system fstab ("/etc/fstab") func ParseSystem() (mounts Mounts, err error) { return ParseFile("/etc/fstab") } // ParseProc parses procfs information func ParseProc() (mounts Mounts, err error) { return ParseFile("/proc/mounts") } // ParseFile parses the given file func ParseFile(filename string) (mounts Mounts, err error) { file, err := os.Open(filename) if nil != err { return nil, err } else { defer file.Close() return Parse(file) } } func Parse(source io.Reader) (mounts Mounts, err error) { mounts = make([]*Mount, 0, 10) scanner := bufio.NewScanner(source) lineNo := 0 for scanner.Scan() { lineNo++ mount, err := ParseLine(scanner.Text()) if nil != err { return nil, fmt.Errorf("Syntax error at line %d: %s", lineNo, err) } if nil != mount { mounts = append(mounts, mount) } } if err := scanner.Err(); err != nil { return nil, err } return mounts, nil } golang-github-d-tux-go-fstab-0.0.0+git.2014.12.04.eb4090f265/mount.go000066400000000000000000000117661244007676000236230ustar00rootroot00000000000000package fstab import ( "fmt" "reflect" "strconv" "strings" ) // Mount represetnts the filesystem info type Mount struct { // The block special device or remote filesystem to be mounted Spec string // The mount point for the filesystem File string // The type of the filesystem VfsType string // Mount options associated with the filesystem MntOps map[string]string // Used by dump to determine which filesystems need to be dumped. Freq int // Used by the fsck(8) program to determine the order in which filesystem checks are done at reboot time PassNo int } type DeviceIdentifierType int const ( Path DeviceIdentifierType = iota Label DeviceIdentifierType = iota UUID DeviceIdentifierType = iota PartUUID DeviceIdentifierType = iota PartLabel DeviceIdentifierType = iota ) // parseOptions parses the options field into an array of strings func parseOptions(optionsString string) (options map[string]string) { options = make(map[string]string) for _, option := range strings.Split(optionsString, ",") { bits := strings.Split(strings.TrimSpace(option), "=") if len(bits) > 1 { options[bits[0]] = bits[1] } else { options[bits[0]] = "" } } return } // MntOpsString returns the serialized MntOps value func (mount *Mount) MntOpsString() (opsstring string) { first := true for key, value := range mount.MntOps { if first { first = false } else { opsstring += "," } opsstring += key if "" != value { opsstring += "=" + value } } return } // String serializes the object into fstab format func (mount *Mount) String() string { return mount.format("%s %s %s %s %d %d") } // format serializes the object according to the given format func (mount *Mount) format(format string) string { return fmt.Sprintf(format, mount.Spec, mount.File, mount.VfsType, mount.MntOpsString(), mount.Freq, mount.PassNo) } // PaddedString serializes the objet into fstab format with configurable column width. // Each positional argument specifies the width for the column in order. Up to 6 arguments // are supported, outstanding arguments will be ignored. func (mount *Mount) PaddedString(paddings ...int) string { stringPaddings := 4 intPaddings := 2 if len(paddings) < stringPaddings { stringPaddings = len(paddings) intPaddings = 0 } else { intPaddings = len(paddings) - stringPaddings if intPaddings > 2 { intPaddings = 2 } } var fields []string = make([]string, 0, 6) { for _, padding := range paddings[:stringPaddings] { fields = append(fields, "%-"+strconv.Itoa(padding)+"s") } for i := len(fields); i < 4; i++ { fields = append(fields, "%s") } } if intPaddings > 0 { for _, padding := range paddings[4:(4 + intPaddings)] { fields = append(fields, "%"+strconv.Itoa(padding)+"d") } } for i := len(fields); i < 6; i++ { fields = append(fields, "%d") } fmt.Printf("%d %d\n%v\n%v\n", stringPaddings, intPaddings, paddings, fields) return mount.format(strings.Join(fields, " ")) } func (mount *Mount) IsSwap() bool { return "swap" == mount.VfsType } func (mount *Mount) IsNFS() bool { return "nfs" == mount.VfsType } // Equals compares 2 Mount objects func (mount *Mount) Equals(other *Mount) bool { return reflect.DeepEqual(*mount, *other) } // SpecType returns the device identifier type func (mount *Mount) SpecType() (spectype DeviceIdentifierType) { bits := strings.Split(mount.Spec, "=") switch strings.ToUpper(bits[0]) { case "UUID": spectype = UUID case "LABEL": spectype = Label case "PARTUUID": spectype = PartUUID case "PARTLABEL": spectype = PartLabel default: spectype = Path } return } // SpecType returns the device identifier value; that is if Spec is // "UUID=vogons-ate-my-sandwich", it will return "vogons-ate-my-sandwich" func (mount *Mount) SpecValue() string { bits := strings.Split(mount.Spec, "=") if 1 == len(bits) { return mount.Spec } else { return bits[1] } } // ParseLine parses a single line (of an fstab). // It will most frequently return a Mount; however, // If a parsing error occurs, `err` will be non-nil and provide an error message. // If the line is either empy or a comment line, `mount` will also be nil. func ParseLine(line string) (mount *Mount, err error) { line = strings.TrimSpace(line) // Lines starting with a pound sign (#) are comments, and are ignored. So are empty lines. if ("" == line) || (line[0] == '#') { return nil, nil } fields := strings.Fields(line) if len(fields) < 4 { return nil, fmt.Errorf("too few fields (%d), at least 4 are expected", len(fields)) } else { mount = new(Mount) mount.Spec = fields[0] mount.File = fields[1] mount.VfsType = fields[2] mount.MntOps = parseOptions(fields[3]) var convErr error if len(fields) > 4 { mount.Freq, convErr = strconv.Atoi(fields[4]) if nil != convErr { return nil, fmt.Errorf("%s is not a number", fields[4]) } } if len(fields) > 5 { mount.PassNo, convErr = strconv.Atoi(fields[5]) if nil != convErr { return nil, fmt.Errorf("%s it not a number", fields[5]) } } } return } golang-github-d-tux-go-fstab-0.0.0+git.2014.12.04.eb4090f265/mount_test.go000066400000000000000000000026131244007676000246510ustar00rootroot00000000000000package fstab import ( "strings" "testing" ) var successfulParseLineExpectations map[string]Mount = map[string]Mount{ "/dev/sda / ext4 defaults 1 2": Mount{ "/dev/sda", "/", "ext4", map[string]string{ "defaults": "", }, 1, 2, }, "UUID=homer / ext4 rw,uid=0": Mount{ "UUID=homer", "/", "ext4", map[string]string{ "uid": "0", "rw": "", }, 0, 0, }, } var successfulMountStringExpectations map[string]Mount = map[string]Mount{ "/dev/sda / ext4 defaults 1 2": Mount{ "/dev/sda", "/", "ext4", map[string]string{ "defaults": "", }, 1, 2, }, "UUID=homer / ext4 uid=0 0 0": Mount{ "UUID=homer", "/", "ext4", map[string]string{ "uid": "0", }, 0, 0, }, } func TestParseLine(t *testing.T) { for line, expectation := range successfulParseLineExpectations { mount, err := ParseLine(line) if nil != err { t.Errorf("Unexpected parse error while parsing '%s': %s", line, err) continue } if !mount.Equals(&expectation) { t.Errorf("Expected %+v, got %+v", expectation, mount) } if 0 == strings.Index(mount.Spec, "UUID") && mount.SpecType() != UUID { t.Errorf("Expected SpecType to be UUID") } } } func TestMountString(t *testing.T) { for expectation, mount := range successfulMountStringExpectations { str := mount.String() if str != expectation { t.Errorf("Expected '%s', got '%s'", expectation, str) } } }