Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

env only works on linux-like systems #178

Closed
abarnert opened this issue Feb 8, 2015 · 1 comment
Closed

env only works on linux-like systems #178

abarnert opened this issue Feb 8, 2015 · 1 comment

Comments

@abarnert
Copy link
Contributor

abarnert commented Feb 8, 2015

The fix for #162 uses env -0, which is a GNU extension that isn't part of POSIX, BSD, etc., which means a whole lot of things now break on OS X, FreeBSD, etc.

As far as I know, there is no perfect portable fix for #162; for example, the standard env command will produce the exact same output for these two cases:

env a=foo b=bar
env a='foo
b=bar'

As far as I know, the only way to do it reliably and portably (at least to anything that's compatible with BSD3 or later, which is a lot more than just GNU…) from the shell is to first get a (potential) list of names by calling and parsing env or printenv, and then lookup each name one by one with printenv.

Of course that can obviously cause performance problems. You can solve that for GNU systems by trying env -0 first and only falling back if that fails:

    env0 = session.run("env -0; echo")
    if env0[0] == 0 and not env 0[2].rstrip():
        self._curr = dict(line.split('=', 1)
                          for line in env0[1].split('\x00')
                          if '=' in line)
    else:
        lines = self.remote._session.run("env; echo")[1].splitlines()
        split = (line.split('=', 1) for line in lines)
        keys = (line[0] for line in split if len(line)>1)
        runs = ((key, session.run('printenv "%s"; echo' % key))
                for key in keys)
        self._curr = dict((key, run[1].rstrip('\n')) for (key, run) in runs
                          if run[0] == 0 and run[1].rstrip('\n')
                          and not run[2])

Alternatively, for platforms without env -0, you can use some heuristics on the output of env, which aren't perfect, but may be good enough for most users.

Your existing code already skips any line without a =; this will truncate variables with embedded newlines, and it will mean that a='foo\nb=bar' will give you a fake variable b, but maybe that's acceptable.

You can eliminate the first problem by treating any line that doesn't start with a valid name followed by = as a continuation of the previous line, as in pigay's suggested patch for #162.

But there's no way to eliminate the last problem. I don't think that's likely to fail too often by accident… but you might want to think about whether someone could engineer some exploit that takes advantage of it.

abarnert added a commit to abarnert/plumbum that referenced this issue Feb 8, 2015
- Since `env -0` is a GNU extension, we need some fallback for OS X, etc.

- Parsing `env` into `name=value` lines (skipping the ones without `=`),
  then calling `printenv $name` on each name (skipping the ones that
  don't exist) should work portably, although obviously more slowly.
tomerfiliba added a commit that referenced this issue Mar 24, 2015
Fall back to `printenv` per variable if no `env -0` (#178).
@henryiii
Copy link
Collaborator

I believe this was fixed with #179. Closing.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants