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

minidlna: Wait for resources (network, disk) to be brought up #5463

Closed
peci1 opened this issue Jan 16, 2018 · 22 comments
Closed

minidlna: Wait for resources (network, disk) to be brought up #5463

peci1 opened this issue Jan 16, 2018 · 22 comments

Comments

@peci1
Copy link

peci1 commented Jan 16, 2018

Maintainer: @medaved
Environment: TurrisOS (fork of OpenWRT, but minidlna is basically unchanged)

Description:

My system is probably specific by its slow network setup (probably due to the VDSL WAN, which somehow takes about a minute to connect). I'm only running minidlna on br-lan, but even this interfaces' startup is delayed by the WAN setup. And this slow setup started to show that minidlna is unable to start using the init scripts.

When I run the init script manually after the router has booted, the minidlna daemon works as expected. So I expect that minidlna doesn't start during boot because the interface is not ready when the init script is run.

Looking through the init script, there's no mention of waiting for the interface to show up. The question is: should a wait for correct interface state be added to the init script?

Or, maybe as a better solution - should the init script be changed to a hotplug.d/iface script? I can imagine that if the network interface would not come up for some reason, the minidlna startup script should not block the start of the rest of init scripts.

@peci1
Copy link
Author

peci1 commented Jan 17, 2018

Related: https://bugs.archlinux.org/task/35325 . Solved by waiting for network.

@peci1
Copy link
Author

peci1 commented Jan 17, 2018

And of course minidlna is enabled for auto startup:

# ll /etc/rc.d/S95minidlna
lrwxrwxrwx    1 root     root            18 Oct 17 23:28 /etc/rc.d/S95minidlna -> ../init.d/minidlna

After a fresh boot, the state of my minidlna is the following:

  • The PID file doesn'texist
  • No minidlna process
  • The logfile /var/log/minidlna.log doesn't exist
  • /var/log/messages doesn't contain anything related to minidlna
  • The /tmp/minidlna.conf file exists with the following contents:
# this file is generated automatically, don't edit
port=8200
network_interface=br-lan
friendly_name=Turris DLNA Server
db_dir=/tmp/run/mountd/sda1/video
log_dir=/var/log
inotify=yes
enable_tivo=no
strict_dlna=no
album_art_names=Cover.jpg/cover.jpg/AlbumArtSmall.jpg/albumartsmall.jpg/AlbumArt.jpg/albumart.jpg/Album.jpg/album.jpg/Folder.jpg/folder.jpg/Thumb.jpg/thumb.jpg
notify_interval=900
serial=12345678
model_number=1
root_container=B
media_dir=V,/tmp/run/mountd/sda1/video
media_dir=P,/tmp/run/mountd/sda1/Backup/D/Fotky
media_dir=V,/tmp/run/mountd/sda1/Backup/D/Fotky

From these symptoms I assume the init script has been run (/tmp/minidlna.conf exists), but did not succeed.

@peci1
Copy link
Author

peci1 commented Jan 17, 2018

Finally I managed to get some debug output from minidlna at boot, and the issue is a bit different, but I'd say also similar:

[2018/01/17 03:08:34] utils.c:279: warn: make_dir: cannot create directory '/tmp/run/mountd/sda1/'
[2018/01/17 03:08:35] minidlna.c:658: fatal: Database path not accessible! [/tmp/run/mountd/sda1/video]

So instead of waiting for network interface, we have to wait for the device where db_dir resides!

@peci1 peci1 changed the title minidlna: Wait for network interface until it is brought up minidlna: Wait for resources (network, disk) to be brought up Jan 17, 2018
@peci1
Copy link
Author

peci1 commented Jan 17, 2018

This is a solution that works for me (this code goes right above the service_start command in the init script):

        config_get interface config 'interface' 'br-lan'

        startup_log="/var/log/minidlna-startup.log"
        rm "$startup_log"

        while ! mkdir -m 0755 -p $db_dir; do
                echo "Waiting for db_dir" >> "$startup_log"
                sleep 1
        done

        while ! mkdir -m 0755 -p $log_dir; do
                echo "Waiting for log_dir" >> "$startup_log"
                sleep 1
        done

        while [[ $(/usr/sbin/ip addr show $interface | wc -l) -eq 0 ]] ; do
                echo "Waiting for $interface" >> "$startup_log"
                sleep 1
        done

Would it be an acceptable thing to do? Should I convert it to a PR, or is there something totally wrong with my approach?

@poranje
Copy link
Contributor

poranje commented Jan 17, 2018 via email

@peci1
Copy link
Author

peci1 commented Jan 17, 2018

@poranje br-lan is just a default for config_get. So what's the magic value that tells minidlna to autodetect the interface? Empty string? I'd say that if no interface is specified, the init script should not wait for network (since then it would have to duplicate the internal interface selection mechanism).

This script also has problems when there are more comma-separated interfaces in the config (which is allowed). It was just an initial piece of code that should show the direction I used, and it probably needs more polishing to be production-ready.

@poranje
Copy link
Contributor

poranje commented Jan 17, 2018 via email

@peci1
Copy link
Author

peci1 commented Jan 17, 2018

And what about the block devices? Also hotplug? Could there be a single script launched from both interface- and block-hotplug, that checks if all conditions are met?

@EricLuehrsen
Copy link
Contributor

EricLuehrsen commented Jan 18, 2018

minidlna could benefit from procd. Using start_service(), stop_service(), and service_triggers() methods instead of former initd start, stop, and such. Unbound, dnsmasq, and adblock are good examples. Note carefully the boot symbol used to exit start_service() early so only service_triggers() are loaded. The following is a code snippet for service_triggers().

local trigger="$(uci_get minidlna.minidlna[0].network_trigger)"
# set delay a bit longer; minidlna can load disk access
PROCD_RELOAD_DELAY=10000
# trigger load from on network; default 'lan' from /etc/config/network
procd_add_reload_interface_trigger "$trigger"

@peci1
Copy link
Author

peci1 commented Jan 24, 2018

@EricLuehrsen Okay, and what about filepath-based triggers? It doesn't seem to me procd supports them...

@peci1
Copy link
Author

peci1 commented Feb 12, 2018

I did some research on the topic of filepath triggers. It seems they're just not there.

But they could (at least to some extent) be added. There are several ways on how to do it:

  1. Inotify. I'm just not sure if it'd be valid/acceptable to require inotify. And I'm sure it doesn't work with many network-mapped filesystems.
  2. Piggy-backing on mountd. After searching through the sources of mountd, it seems that it updates a file called /var/state/mountd every time it automounts a drive. This could be utilized somehow to broadcast a raw trigger like in https://github.com/openwrt/openwrt/blob/master/package/network/utils/linux-atm/files/atm.hotplug .
  3. Utilizing the hotplug mechanism somehow to broadcast a raw trigger.

At least for the inotify case, there's no need for a super-precise mechanism that'd be able to report the exact path that has (dis)appeared. I think it's sufficient to know some mounts appeared/disappeared, and leave it to the init script to determine if it was a mount of interest.

From this point of view, I'd prefer hotplug, but it seems to me it is being deprecated. Am I right?

@poranje
Copy link
Contributor

poranje commented Feb 12, 2018 via email

@peci1
Copy link
Author

peci1 commented Feb 13, 2018

@poranje Yes, that's one of the options. I'm new to OpenWRT, so I don't have enough experience to decide what's the best design. Would it be a good way to send a (raw) trigger from that hotplug script and subscribe for it in the minidlna procd script (as is done in the atm example referenced above)?

One offtopic:
Despite I've digged very intensely, I can't find much about how the interface procd triggers are generated. It seems that the ubus service object's method event can receive data of structure {'type':String, 'data': Table}, and the _procd_add_reload_interface_trigger method from /lib/functions/procd.sh adds a trigger of type interface.*. I even found that in after event is called (published to?) over ubus, it calls method trigger_handle from procd/service/trigger.c. And this method should then invoke all the triggers registered in the startup scripts. However, I haven't found a single place in the code where something'd publish event of type interface.something. The kernel uevents generated by networking drivers use subsystem net, and netifd creates separate ubus objects called network.interface.something. So I really don't know how does it happen that something triggers the interface.* triggers (and it probably does, because some startup scripts rely on that).

@neheb
Copy link
Contributor

neheb commented Jan 22, 2020

Can someone test this: #11004 ?

@peci1
Copy link
Author

peci1 commented Jan 29, 2020

@neheb I don't see how #11004 would solve this issue. The startup script, though converted to procd, still contains mkdir $log_dir without making sure that the drive $log_dir is located on is actually present.

@neheb
Copy link
Contributor

neheb commented Feb 4, 2020

I increased the start value. That should fix it.

@peci1
Copy link
Author

peci1 commented Feb 4, 2020

That should help. But I wouldn't call it a fix, as the configuration options are endless and you can't know when and how does the user set up his network and disks...

@luizluca
Copy link
Contributor

luizluca commented Feb 4, 2020

Systemd could fix that class of problem, not procd (which is more like sysv).

The network issue could he solved with some script and hotplug. Minidlna knows which network it needs. A wrapper around minidlna bin could check if the network is missing. If so, create a named pipe /var/run/minidlna/pending and read that in a loop. That will block the script until someone write to it. An iface hotplug could check if that named pipe exists and write it once any network is up, releasing the script. If network was what it needed, exec minidlna binary. If not, read named pipe again. A timeout, if needed, could be used to kill the blocked script after some time.

Stopping the service will kill the script/minidlna and should remove any named pipe.

Now the missing path is another topic. I'm not aware of any hotplug related to a mounted filesystem. I guess hotplug/block script would call mount, not the other way around. Who mounts fs is block-mount. Maybe it could emit a new hotplug event. However, monitoring fs is an inotify job. And I'm still not sure it is needed.

Mounts happens in S40fstab service. It is a non-procd script. I did not test but it might not be async, blocking boot until all available devices are mounted. If it blocks, it would be enough to have minidlna at S50. If not, we could add to it something like S95done to it. We do not have a 'udevadm settle' but devices are listed (coldplug) in procd early stage and modules loaded before services are started. When fstab exits, everything should be in their place. If not, there is room to fix that there (like a new "block done" or "udevadm settle" alike).

I don't like the current 'mkdir -p' approach for db. It could make sense for a tmpfs but not for a persistent path (or when the user change it). I get an useless minidlna db in my overlay and a useless service when the fs where it would be is not mounted. I would prefer to have it fails if parent folder is missing.

@neheb
Copy link
Contributor

neheb commented Feb 4, 2020

Sounds overly complicated.

Could just terminate the script in case mkdir fails.

@neheb
Copy link
Contributor

neheb commented Feb 9, 2020

@peci1 please retest. log_dir is gone now.

@peci1
Copy link
Author

peci1 commented Feb 10, 2020

Okay. But I'll get to it earliest in March...

@peci1
Copy link
Author

peci1 commented Aug 18, 2022

I haven't seen any problem with minidlna startup for a long time, so I'm closing this issue. Thanks for the workaround/fix.

@peci1 peci1 closed this as completed Aug 18, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

5 participants