jcorporation / myMPD

myMPD is a standalone and mobile friendly web mpd client with a tiny footprint and advanced features.
https://jcorporation.github.io/myMPD/
GNU General Public License v3.0
418 stars 65 forks source link

Linux build: on some circumstances cmake installs wrong startup script #1152

Closed nousernouser closed 11 months ago

nousernouser commented 11 months ago

myMPD version: 13.0.1

Many distributions that are installed using systemd as the default init system can also be installed using different init systems (for example: Debian); the running init system can also be changed after installation.

Likewise, many distributions that use a non-systemd init system by default, allow to choose systemd during installation; or to change the init system after installation.

Then, various situations can arise in those systems which still retain a /lib/systemd/system or /usr/lib/systemd/system directory even though an init system other than systemd is in use: in these cases, the myMPD-master/cmake/Install.cmake.in script fails as it installs (only) the systemd startup script and do not install the actual startup script.

I think this is due to the if--elif structure used in the myMPD-master/cmake/Install.cmake.in script:

if("@MYMPD_STARTUP_SCRIPT@" STREQUAL "ON")

Install startup script

if(EXISTS "/lib/systemd/system" OR EXISTS "/usr/lib/systemd/system")

Install systemd unit

...

elseif(EXISTS "/sbin/openrc-run")

Install openrc script

...

elseif(EXISTS "/etc/init.d")

Install sysVinit script

...

elseif(EXISTS "/bin/freebsd-version")

Install FreeBSD rc script

...

else() message("No supported init system found, no startup script was installed") endif() endif()

I think the best solution would be changing the if--elif structure in the script, using a simple if-sequence so that startup scripts are installed for all the init systems supported by the distribution:

if("@MYMPD_STARTUP_SCRIPT@" STREQUAL "ON")

Install startup script -- systemd

if(EXISTS "/lib/systemd/system---" OR EXISTS "/usr/lib/systemd/system---")

Install systemd unit

...
set(MYMPD_INIT_FOUND TRUE)
message("Systemd unit was installed")

endif()

Install startup script -- other: non-systemd

if(EXISTS "/sbin/openrc-run")

Install openrc script

...
set(MYMPD_INIT_FOUND TRUE)
message("Openrc startup script was installed")

endif() if(EXISTS "/etc/init.d")

Install sysVinit script

...
set(MYMPD_INIT_FOUND TRUE)
message("sysVinit startup script was installed")

endif() if(EXISTS "/bin/freebsd-version")

Install FreeBSD rc script

...
set(MYMPD_INIT_FOUND TRUE)
message("FreeBSD startup script was installed")

endif() if(NOT MYMPD_INIT_FOUND) message("No supported init system found, no startup script was installed") endif() endif()

Expected behavior

The mympd sysV init script should be installed (better both the systemd unit and the sysV init script should be installed)

To Reproduce

Steps to reproduce the behavior:

You have a running Linux distrubution using a non-systemd init system but still retaining /lib/systemd/system or /usr/lib/systemd/system -- it can be: Debian installed with systemd and after moved to OpenRC; or Devuan which has sysVinit by default but also has /lib/systemd/system directory; or other possible similar situations with various distributions...

Say we have Devuan + sysVinit with the /lib/systemd/system directory present in the file system

  1. Buid myMPD from the sources and install
  2. The systemd unit will be installed, but the mympd sysV init script is missing

Plattform:

jcorporation commented 11 months ago

I do not think your proposal is better, e.g. /etc/init.d exists for openrc based distributions. It merely shifts the problem.

For special cases, it could be better to extend the available options for the MYMPD_STARTUP_SCRIPT compile time option. Then you can choose at compile time, which startup script should be installed.

What do you think?

nousernouser commented 11 months ago

Hi Jürgen

Suppose to make a fresh installation of a system (it could be Debian) choosing OpenRC (or Sysvinit) as Init.

Then when the user installs a prebuild .deb package (from the repositories, for example https://download.opensuse.org/repositionies/home:/jcorporation/debian_12/amd64/...), the current myMPD-master/cmake/Install.cmake.in script fails because it finds /lib/systemd/system and the if-elif structure installs the Systemd Unit only, but does not install the OpenC (or Sysvinit) startup script.

Furthermore, it may happen that a user decides to change the init system of a running system: this would break a working myMPD installation, because the corresponding script would be missing.

Yes, extending the available options for the MYMPD_STARTUP_SCRIPT (which pheraphs could also be a list) compile time option could be a solution, but it requires the user to recompile the package, or that several versions of the package are provided in the repositories, one for each init system, so as to allow the "right" reinstall.

Personally I think it would be better that the myMPD-master/cmake/Install.cmake.in script installs the init scripts for all the init systems which can be found to be supported by the distribution in use.

The advantages would be:

The "cost" would be to have installed the init scripts for all the init systems which can be found as supported by the distribution in use... but in my opinion this would be an advantageous feature, not a cost.

Thanks for your attention

jcorporation commented 11 months ago

Installing all init scripts is not good solution, e.g. the init script for sysvinit and openrc has the same install location and name. The best approach could be to install the init scripts through the post install script of the packages.

I wonder how other not distribution specific packages handles this?

nousernouser commented 11 months ago

Installing all init scripts is not good solution, e.g. the init script for sysvinit and openrc has the same install location and name.

Hum... You are right.

The best approach could be to install the init scripts through the post install script of the packages.

Yes this could be a good approach.

I wonder how other not distribution specific packages handles this?

Indeed things seems to be complex...

If using a post install script, I have found an interesting thread:

https://unix.stackexchange.com/questions/18209/detect-init-system-using-the-shell where seem to me be relevant these posts: https://unix.stackexchange.com/a/18210 https://unix.stackexchange.com/a/114616 https://unix.stackexchange.com/a/18218 https://unix.stackexchange.com/a/513187

Other useful ideas here: https://linuxhandbook.com/check-if-systemd/ (the ps and/or stat approach seem good and portable)

and here: https://www.2daygeek.com/how-to-determine-which-init-system-manager-is-running-on-linux-system/

With a post install script, a good solution (based of some of the readings above) could be:

Hope it helps Regards

nousernouser commented 11 months ago

Hi Jürgen

Thinking about the problem, a very simple and good compromise solution could be to modify the myMPD-master/cmake/Install.cmake.in script so that it becomes:

if("@MYMPD_STARTUP_SCRIPT@" STREQUAL "ON")

  # Install startup script -- systemd
  if(EXISTS "/lib/systemd/system---" OR EXISTS "/usr/lib/systemd/system---")
    #Install systemd unit
    ...
    set(MYMPD_INIT_FOUND TRUE)
    message("Systemd unit was installed")
  endif()

  # Install startup script -- other: non-systemd
  if(EXISTS "/sbin/openrc-run")
    #Install openrc script
    ...
    set(MYMPD_INIT_FOUND TRUE)
    message("Openrc startup script was installed")
  elseif(EXISTS "/etc/init.d")
    #Install sysVinit script
    ...
    set(MYMPD_INIT_FOUND TRUE)
    message("sysVinit startup script was installed")
  elseif(EXISTS "/bin/freebsd-version")
    #Install FreeBSD rc script
    ...
    set(MYMPD_INIT_FOUND TRUE)
    message("FreeBSD startup script was installed")
  endif()

  if(NOT MYMPD_INIT_FOUND)
    message("No supported init system found, no startup script was installed")
  endif()

endif()

In this way, the systemd directory is searched first, with an if-endif: if present, the systemd unit is installed.

Then openrc, sysvinit and freesb are searched for, with an if-elseif structure: if one is found, only the corresponding startup script is installed (and the if-eleseif structure is exited).

This would allow you to "handle" problematic situations in which there are systemd directories but the system is using a different init system, also avoiding the /etc/init.d "conflict" between openrc and sysvinit.

Hope it helps

Thank you Regards

jcorporation commented 11 months ago

I do not like the idea to install more than one init script. I can add an option to select the init script through a compile time option.

A distribution packager should have the possibility to choose the right init script.

jcorporation commented 11 months ago

@comburent, @dvzrv as you are packaging for distributions: what are your opinions?

comburent commented 11 months ago

Hi Jürgen,

On 2023-11-09 21:37, Jürgen Mang wrote:

as you are packaging for distributions: what are your opinions?

Guix-wise this isn't much of an issue since it uses its own init system (shepherd) and doesn't rely on the init scripts provided by the packages. (Guix has the concept of “system services” that serves the same purpose)

As for the traditional distribution scenario, I think it might be best to have the init scripts installed via a post-install hook script, which is a mechanism from the distribution side. Reason being that the distributions might want to patch or override the defaults in the init scripts, be it for hardening or accounting for distribution details. In that case, it's better to simply leave these init scripts under contrib/ as “extras” that aren't used by the build system. My 2¢.

Cheers,

-- Bruno.

nousernouser commented 11 months ago

Hi Jürgen,

In my humble opinion, the way you have extended MYMPD_STARTUP_SCRIPT compile time option to select init, is satisfying:

With this approach, the "ON" option appears to be even superfluous, and perhaps could cause confusion. It could be removed.

In any case, let me recommend that build options for installing init scripts be highlighted in the documentation.

Regards

jcorporation commented 11 months ago

Thanks for feedback, closing this issue now.