interfaces/mount: add function for parsing mount entries #3102

Merged
merged 4 commits into from Mar 30, 2017

Conversation

Projects
None yet
4 participants
Contributor

zyga commented Mar 29, 2017

This patch adds a simple function for parsing fstab-like mount entries
along with full suite of tests.

Signed-off-by: Zygmunt Krynicki zygmunt.krynicki@canonical.com

interfaces/mount: add function for parsing mount entries
This patch adds a simple function for parsing fstab-like mount entries
along with full suite of tests.

Signed-off-by: Zygmunt Krynicki <zygmunt.krynicki@canonical.com>
interfaces/mount/entry.go
+// ParseEntry parses a fstab-like entry.
+func ParseEntry(s string) (Entry, error) {
+ var e Entry
+ fields := strings.Fields(s)
@mvo5

mvo5 Mar 29, 2017

Collaborator

The glibc mntent_r.c is using strsep(..., " \t") only, strings.Fields() is using any unicode whitespace. I don't think it makes a difference in practise but I would prefer if we would follow glibc as close as possible.

@zyga

zyga Mar 29, 2017

Contributor

I'll do my best to handle that.

@zyga

zyga Mar 30, 2017

Contributor

After trying with Scanner API I now did this with the trivial strings.FieldsFunc method. Have a look please.

interfaces/mount/entry.go
+ var e Entry
+ fields := strings.Fields(s)
+ // do all error checks before any assignments to `e'
+ if len(fields) != 6 {
@mvo5

mvo5 Mar 29, 2017

Collaborator

The last two fields (fs_freq and fs_passno) are optional and default to 0 if missing. So this needs to be adjusted (happens in the real world).

Also it appears that sometimes fstab entries with more fields exist in the wild, e.g. https://bugs.launchpad.net/ubuntu/+source/update-manager/+bug/873411/comments/7 - we may want to ignore those, this is similar to what glibc is doing).

@zyga

zyga Mar 29, 2017

Contributor

Aha, interesting.

The documented format of fstab doesn't have the extra entries and I don't think we should handle those. The optional aspect of the last two fields is indeed something that is easy to handle so I'll do that quickly. Thanks for noticing that!

@zyga

zyga Mar 29, 2017

Contributor

The last two fields are now optional.

zyga added some commits Mar 29, 2017

interfaces/mount: make dump frequency and check pass number optional
Signed-off-by: Zygmunt Krynicki <zygmunt.krynicki@canonical.com>
interfaces/mount: split fstab entries on [ \t]+
Signed-off-by: Zygmunt Krynicki <zygmunt.krynicki@canonical.com>
interfaces/mount/entry.go
+ " ", `\040`, "\t", `\011`, "\n", `\012`, "\\", `\134`)
+ whitespaceUnescape = strings.NewReplacer(
+ `\040`, " ", `\011`, "\t", `\012`, "\n", `\134`, "\\")
+)
@chipaca

chipaca Mar 30, 2017

Member

you know you could just do

var unescape = strings.NewReplacer(...).Replace

yes?

@zyga

zyga Mar 30, 2017

Contributor

Oh, nice :-) I didn't think about this. Edit: applied :-)

@chipaca

chipaca Mar 30, 2017

Member

the compiler is probably smart enough anyway. Certainly in 1.8 :-)

interfaces/mount: simplify escape/unescape (thanks to chipaca)
Signed-off-by: Zygmunt Krynicki <zygmunt.krynicki@canonical.com>

mvo5 approved these changes Mar 30, 2017

@mvo5 mvo5 merged commit 4052e82 into snapcore:master Mar 30, 2017

1 of 6 checks passed

xenial-amd64 autopkgtest running
Details
xenial-i386 autopkgtest running
Details
xenial-ppc64el autopkgtest running
Details
yakkety-amd64 autopkgtest running
Details
zesty-amd64 autopkgtest running
Details
continuous-integration/travis-ci/pr The Travis CI build passed
Details

@zyga zyga deleted the zyga:parse-fstab-entry branch Mar 30, 2017

A few late suggestions:

-func escape(s string) string {
- return whitespaceReplacer.Replace(s)
-}
+var escape = strings.NewReplacer(" ", `\040`, "\t", `\011`, "\n", `\012`, "\\", `\134`).Replace
@niemeyer

niemeyer Mar 31, 2017

Contributor

Instead of documenting this and then repeating it with code hoping we have both in sync, it'd be better to format the code itself in a way that may be read easily:

var escape = strings.NewReplacer(
        " ", `\040`,
        "\t", `\011`,
        "\n", `\012`,
        "\\", `\134`,
)

That sort of issue shows up very often. Sometimes that's not feasible, but when it is, code that speaks for itself is much better than comments.

@zyga

zyga Mar 31, 2017

Contributor

Sure, I'll format it in a more readable way in a follow-up branch!

+ return e, fmt.Errorf("expected between 4 and 6 fields, found %d", len(fields))
+ }
+ // Parse DumpFrequency if we have at least 5 fields
+ if len(fields) >= 5 {
@niemeyer

niemeyer Mar 31, 2017

Contributor

In general len(fields) > N when you want to use N is easier to read than >= and N-1. So len(fields) > 5 allows you to use fields[5] for example.

+ if len(fields) >= 5 {
+ df, err = strconv.Atoi(fields[4])
+ if err != nil {
+ return e, fmt.Errorf("cannot parse dump frequency: %s", err)
@niemeyer

niemeyer Mar 31, 2017

Contributor

In these cases, rather than printing the error it's much more useful to have the original string quoted:

return e, fmt.Errorf("cannot parse dump frequency: %q", fields[4])

@zyga

zyga Mar 31, 2017

Contributor

Aha, indeed, in fact errors from Atoi look very unreadable (ugly). I'll adjust this.

+ if len(fields) >= 6 {
+ cpn, err = strconv.Atoi(fields[5])
+ if err != nil {
+ return e, fmt.Errorf("cannot parse check pass number: %s", err)
@niemeyer

niemeyer Mar 31, 2017

Contributor

Same.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment