OS permissions error for folder using a watcher (whitelist and file permissions checked)

I’m trying out the folder_watcher integration but I can’t figure out why I’m getting a OSError: Permission denied error (generated by the listener code, AFAICS). It’s close to the example in the docs for this integration.

As far as I can see, I’ve done everything correctly: The folder (directory) I’m watching is /tmp and it’s whitelisted and is world-readable.

The only thing I can think of is that the folder watcher only works on relative paths in the HA config directory, but it’s not clear to me from the docs whether that’s the case.

Minimal config:

homeassistant:
  ...
  whitelist_external_dirs:
    - /tmp

shell_command:
  copy_files: "cp /tmp/test_*.* /home/homeassistant/.homeassistant/www/gallery/"

folder_watcher:
  - folder: /tmp/
    patterns: 
      - "test_*.*"

automation:
  - alias: Copy New File
    initial_state: true
    trigger:
      platform: event
      event_type: folder_watcher
      event_data:
        event_type: created
    action:
      service: shell_command.copy_files

Files, directories and permissions:

/tmp $ ls -lah .
total 180K
drwxrwxrwt 10 root          root           12K May 22 17:39 .
~/.homeassistant/www/gallery $ ls -lah .
total 3.8M
drwxr-xr-x 2 homeassistant homeassistant 4.0K May 22 17:38 .

I’ve called the copy script from the dev tools and that works.

I can’t see anything wrong. I’d appreciate a bit of help.

PS: I’ve had another automation copying files also from /tmp but triggered by a motion sensor and that’s been working forever, so I’m quite certain my whitelist and permissions are fine (at least fine enough for that to work).

How is Home Assistant installed? Docker, Home Assistant(former hassio), venv etc?
I think the www folder is whitelisted by default, but you might need to explicitly whitelist the www/gallery folder. If you are running HA in Docker, that would be /config/www/gallery. If running in a venv, it would be the absolute path instead.

Thanks @tjntomas.

It’s a venv setup on a PI.

The full path to e.g. the config folder is /home/homeassistant/.homeassistant/ (so www is under there).

I did a test using this config and it works when making changes to www but not /tmp (there are no errors in the log):

folder_watcher:
  - folder: /tmp
  - folder: /home/homeassistant/.homeassistant/www

automation:
  - alias: Folder Watcher Test
    trigger:
      platform: event
      event_type: folder_watcher
    action:
      service: notify.mobile_app_xxx
      data_template:
        title: Test
        message: "File {{ trigger.event.data.file }} in {{ trigger.event.data.folder }} was {{ trigger.event.data.event_type }}."
        data:
          file: "{{ trigger.event.data.path }}"

More info:

If I create a folder /foo (at the root of the filesystem, with HA the owner and whitelisted it), that works just fine.

So, it seems /tmp is getting special treatment somehow. Regarding permissions, /tmp has a sticky bit set. Perhaps it’s some kind of security concern to prevent /tmp from being watched?

I’m now digging into the HA core code to see if there’s special treatment and checking the watchdog package’s documentation.

I think I’m on the right track now. From the folder watcher docs:

Note that by default folder monitoring is recursive, meaning that the contents of sub-folders are also monitored.

/tmp contains other files and directories not owned by HA and the OSError I think is raised for that.

I should probably have spotted the reference to “recursive” in the log earlier:

2020-05-28 18:30:07 ERROR (MainThread) [homeassistant.core] Error doing job: Future exception was never retrieved
Traceback (most recent call last):
  File "/usr/lib/python3.7/concurrent/futures/thread.py", line 57, in run
    result = self.fn(*self.args, **self.kwargs)
  File "/srv/homeassistant/lib/python3.7/site-packages/homeassistant/components/folder_watcher/__init__.py", line 112, in startup
    self._observer.start()
  File "/srv/homeassistant/lib/python3.7/site-packages/watchdog/observers/api.py", line 255, in start
    emitter.start()
  File "/srv/homeassistant/lib/python3.7/site-packages/watchdog/utils/__init__.py", line 111, in start
    self.on_thread_start()
  File "/srv/homeassistant/lib/python3.7/site-packages/watchdog/observers/inotify.py", line 121, in on_thread_start
    self._inotify = InotifyBuffer(path, self.watch.is_recursive)
  File "/srv/homeassistant/lib/python3.7/site-packages/watchdog/observers/inotify_buffer.py", line 35, in __init__
    self._inotify = Inotify(path, recursive)
  File "/srv/homeassistant/lib/python3.7/site-packages/watchdog/observers/inotify_c.py", line 187, in __init__
    self._add_dir_watch(path, recursive, event_mask)
  File "/srv/homeassistant/lib/python3.7/site-packages/watchdog/observers/inotify_c.py", line 371, in _add_dir_watch
    self._add_watch(full_path, mask)
  File "/srv/homeassistant/lib/python3.7/site-packages/watchdog/observers/inotify_c.py", line 385, in _add_watch
    Inotify._raise_error()
  File "/srv/homeassistant/lib/python3.7/site-packages/watchdog/observers/inotify_c.py", line 406, in _raise_error
    raise OSError(os.strerror(err))
OSError: Permission denied

So now my question is: If the docs say it’s the default, how do I change this behaviour?

Reading the HA core code it looks quite hard-coded, so I’d say the docs is not accurate. I’d probably have to find another solution to what I’m trying to do.

To summarise: Don’t watch /tmp because the folder watcher integration hardcodes the recursive option and you very likely will have other directories and files in /tmp that won’t be world readable, even if /tmp itself is.