Repository: pypa/pip

Issue:
pip not working without execute/read permission on /etc 
* Pip version:  pip 9.0.1 
* Python version: 2.7.3
* Operating system: Debian

Hi,
I'm doing scientific computations on a Computer cluster. When the sysadmin decided to remove read permissions from /etc pip stopped working, because` os.listdir(_UNIXCONFDIR)` in  [distro.py ](https://github.com/pypa/pip/blob/master/pip/_vendor/distro.py#L984) fails.

As a quick fix I changed the following in my local pip installation:
```python
try:
    basenames = os.listdir(_UNIXCONFDIR)
    # We sort for repeatability in cases where there are multiple
    # distro specific files; e.g. CentOS, Oracle, Enterprise all
    # containing `redhat-release` on top of their own.
    basenames.sort()
except OSError:
    basenames = ["os-release"]
```
This of course requires `/etc/os-release` to be readable.
I just wanted to share this in case someone runs into the same problem!

Best,

Leonhard






Discussion:
As we vendor in ```distro.py```, you should probably report this upstream to them, at https://github.com/nir0s/distro. The diea behind your fix seems reasonable to me (although I'm not a Unix expert). At a minimum I would think that ```distro.py``` should make sure that it never fails in the face of unusual configurations, but just ensures that it returns *something* (although obviously it'll be less and less reliable the more the sysadmin blocks access to the information needed...)
Strongly related to #4249
As #4249 has been resolved, @he-leon could you check if you still have the problem with distro-1.0.3 ?

Running `python -c "import distro;print(distro.linux_distribution())"` with latest distro should be enough.
I think this one is still a bug looking at the code, the ``os.listdir`` is still there.
Still having the same error with 1.0.3:
```
% pip2 show distro
Name: distro
Version: 1.0.3
Summary: Linux Distribution - a Linux OS platform information API
Home-page: https://github.com/nir0s/distro
Author: Nir Cohen
Author-email: nir36g@gmail.com
License: Apache License, Version 2.0
Location: /home/XXX/.local/lib/python2.7/site-packages
```

```
% python2 -c "import distro;print(distro.linux_distribution())"
Traceback (most recent call last):
  File "<string>", line 1, in <module>
  File "/home/XXX/.local/lib/python2.7/site-packages/distro.py", line 1056, in <module>
    _distro = LinuxDistribution()
  File "/home/XXX/.local/lib/python2.7/site-packages/distro.py", line 597, in __init__
    self._distro_release_info = self._get_distro_release_info()
  File "/home/XXX/.local/lib/python2.7/site-packages/distro.py", line 986, in _get_distro_release_info
    basenames = os.listdir(_UNIXCONFDIR)
OSError: [Errno 13] Permission denied: '/etc'
```


@he-leon as a workaround you should be able to tell distro to check somewhere else via the `UNIXCONFDIR` environment variable (cf https://github.com/nir0s/distro/issues/149).
@xavfernandez Thanks! I'll try it out!
Filed upstream as https://github.com/nir0s/distro/issues/174.

Resolving patch:
diff --git a/pip/_vendor/distro.py b/pip/_vendor/distro.py
--- a/pip/_vendor/distro.py
+++ b/pip/_vendor/distro.py
@@ -982,11 +982,29 @@ def _get_distro_release_info(self):
                 distro_info['id'] = match.group(1)
             return distro_info
         else:
-            basenames = os.listdir(_UNIXCONFDIR)
-            # We sort for repeatability in cases where there are multiple
-            # distro specific files; e.g. CentOS, Oracle, Enterprise all
-            # containing `redhat-release` on top of their own.
-            basenames.sort()
+            try:
+                basenames = os.listdir(_UNIXCONFDIR)
+                # We sort for repeatability in cases where there are multiple
+                # distro specific files; e.g. CentOS, Oracle, Enterprise all
+                # containing `redhat-release` on top of their own.
+                basenames.sort()
+            except OSError:
+                # This may occur when /etc is not readable but we can't be
+                # sure about the *-release files. Check common entries of
+                # /etc for information. If they turn out to not be there the
+                # error is handled in `_parse_distro_release_file()`.
+                basenames = ['SuSE-release',
+                             'arch-release',
+                             'base-release',
+                             'centos-release',
+                             'fedora-release',
+                             'gentoo-release',
+                             'mageia-release',
+                             'manjaro-release',
+                             'oracle-release',
+                             'redhat-release',
+                             'sl-release',
+                             'slackware-version']
             for basename in basenames:
                 if basename in _DISTRO_RELEASE_IGNORE_BASENAMES:
                     continue


Test patch: