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

Makefile.am, configure.ac, NEWS.adoc: implement make install-as-root [#1298] #2761

Merged
merged 14 commits into from
Jan 15, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 26 additions & 4 deletions INSTALL.nut.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -306,11 +306,30 @@ Installation

[NOTE]
=====================================================================
You should now gain privileges for installing software if necessary, e.g.:

you should now gain privileges for installing software if necessary:
su -

su
or prefix installation (not build/check!) commands with `sudo`, e.g.:

sudo make install ...
=====================================================================

[NOTE]
=====================================================================
If you install NUT for direct consumption on the system that has just
built it from source, you might be aided for some of the steps listed
and explained below by running (as `root`):

make install-as-root

This should not only install the software, but also create directories
such as the state path, assign ownership and access permissions to
certain directories and sample configuration files which NUT user
and/or group accounts should be able to read and/or write, and, on
some platforms, also (re-)start the NUT daemons/services.

See above "System User creation", that should be done first!
=====================================================================

Install the files to a system level directory:
Expand All @@ -328,7 +347,7 @@ have created.

If you are packaging this software, then you will probably want to
use the DESTDIR variable to redirect the build into another place,
i.e.:
also known as a "prototype directory" or a "staging area", i.e.:

make DESTDIR=/tmp/package install
make DESTDIR=/tmp/package install-conf
Expand All @@ -337,9 +356,12 @@ i.e.:
State path creation
^^^^^^^^^^^^^^^^^^^

NOTE: See above about `make install-as-root`, if you use that -- skip
this step here.

Create the state path directory for the driver(s) and server to use
for storing UPS status data and other auxiliary files, and make it
group-writable by the group of the system user you created.
group-writable by the group of the system user you created, e.g.:

mkdir -p /var/state/ups
chmod 0770 /var/state/ups
Expand Down
195 changes: 195 additions & 0 deletions Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -526,6 +526,201 @@ setver:
@echo "Error: 'make setver' no longer exists."
@echo "Edit configure.ac to set version number."

# Adjust permissions when installing as `root` into the actual system.
# We honour DESTDIR anyway, as someone can install into a chroot etc.
# NOTE: Might be an 'install-data-hook' (for dirs) and/or 'install-exec-hook'
# (for service restart) but better not force this on everyone?
# It is also up to the end-user making such an installation to remove (or not)
# dirs and files made below.
# To err on the safe side in cross builds, we ignore Windows builds and those
# not built for the same system as the build host.
install-data-hook:
@case "@target_os@" in *mingw*) exit 0;; esac ; \
if [ x"@host_os@" != x"@build_os@" ]; then exit 0 ; fi ; \
if [ x"@target_os@" != x"@build_os@" ]; then exit 0 ; fi ; \
if (command -v id) && [ x"`id -u`" = x0 ] && [ x"$(DESTDIR)" = x -o x"$(DESTDIR)" = x/ ] ; then \
echo "================================================================================" >&2 ; \
echo "| NUT data files have been installed into the system, now consider running |" >&2 ; \
echo "| '(sudo) make install-as-root' to apply permissions and service state changes |" >&2 ; \
echo "================================================================================" >&2 ; \
fi

if HAVE_SYSTEMD
HAVE_SYSTEMD = true
else
HAVE_SYSTEMD = false
endif

if WITH_SYSTEMD_TMPFILES
WITH_SYSTEMD_TMPFILES = true
else
WITH_SYSTEMD_TMPFILES = false
endif

if WITH_SYSTEMD_PRESET
WITH_SYSTEMD_PRESET = true
else
WITH_SYSTEMD_PRESET = false
endif

if WITH_CGI
WITH_CGI = true
else
WITH_CGI = false
endif

if WITH_SOLARIS_SMF
WITH_SOLARIS_SMF = true
else
WITH_SOLARIS_SMF = false
endif

if WITH_SOLARIS_INIT
WITH_SOLARIS_INIT = true
else
WITH_SOLARIS_INIT = false
endif

# TODO: Actually move this into scripts like Solaris/postinstall
# using OS-specific `useradd`/`groupadd`, etc.
# Note that as we stop services, we may be dealing with (older)
# distros that do not follow current naming in NUT code base.
install-as-root:
@+echo "$@: starting (no-op if not root)" >&2 ; \
case "@target_os@" in *mingw*) exit 0;; esac ; \
if [ x"@host_os@" != x"@build_os@" ]; then exit 0 ; fi ; \
if [ x"@target_os@" != x"@build_os@" ]; then exit 0 ; fi ; \
prefix="@prefix@"; \
if (command -v id) && [ x"`id -u`" = x0 ] ; then \
if [ x"$(DESTDIR)" = x -o x"$(DESTDIR)" = x/ ] ; then \
if $(HAVE_SYSTEMD) ; then \
echo "$@: Stop NUT services, if any" >&2 ; \
@SYSTEMD_SYSTEMCTL_PROGRAM@ stop nut-monitor.service nut-server.service || true ; \
@SYSTEMD_SYSTEMCTL_PROGRAM@ stop nut-driver.service || true ; \
@SYSTEMD_SYSTEMCTL_PROGRAM@ stop nut-driver.target || true ; \
@SYSTEMD_SYSTEMCTL_PROGRAM@ stop nut.target || true ; \
fi ; \
if $(WITH_SOLARIS_SMF) || $(WITH_SOLARIS_INIT) ; then \
if $(WITH_SOLARIS_SMF) ; then \
echo "$@: Stop NUT services, if any" >&2 ; \
SMF_ACTIVE="`/usr/bin/svcs -a -Hostate,fmri | grep svc:/system/power/ | grep -v disabled | awk '{print $$2}'`" ; \
for S in $$SMF_ACTIVE ; do \
/usr/sbin/svcadm disable -ts $$S || true ; \
done ; \
fi ; \
$(top_builddir)/scripts/Solaris/preremove \
|| exit ; \
fi ; \
fi ; \
$(MAKE) $(AM_FLAGS) DESTDIR="$(DESTDIR)" install || exit ; \
if [ x"$(DESTDIR)" = x -o x"$(DESTDIR)" = x/ ] ; then \
if $(WITH_SOLARIS_SMF) || $(WITH_SOLARIS_INIT) ; then \
$(top_builddir)/scripts/Solaris/preinstall && \
$(top_builddir)/scripts/Solaris/postinstall ; \
exit ; \
fi ; \
fi ; \
echo " MKDIR $(DESTDIR)/@STATEPATH@ $(DESTDIR)/@STATEPATH@/upssched" >&2 ; \
$(MKDIR_P) "$(DESTDIR)/@STATEPATH@/upssched" && \
for D in "@PIDPATH@" "@ALTPIDPATH@" "@ALTSTATEPATH@" "@CONFPATH@" ; do \
case x"$$D" in \
x|x@*) ;; \
*) echo " MKDIR $(DESTDIR)/$$D" >&2 ; \
$(MKDIR_P) "$(DESTDIR)/$$D" \
|| exit ;; \
esac ; \
done ; \
if (command -v chmod) ; then \
echo " CHMOD(0770) $(DESTDIR)/@STATEPATH@/upssched" >&2 ; \
chmod 0770 "$(DESTDIR)/@STATEPATH@/upssched" \
|| exit ; \
for D in "@STATEPATH@" "@PIDPATH@" "@ALTPIDPATH@" "@ALTSTATEPATH@" ; do \
case x"$$D" in \
x|x@*|x/run|x/var/run|x/tmp|x/var/tmp|x/dev/shm|x/etc|x/var|x/usr|x/usr/local|x/usr/local/etc|x/usr/etc) ;; \
*) echo " CHMOD(0770) $(DESTDIR)/$$D" >&2 ; \
chmod 0770 "$(DESTDIR)/$$D" \
|| exit ;; \
esac ; \
done ; \
case x"@CONFPATH@" in \
x|x@*|x/run|x/var/run|x/tmp|x/var/tmp|x/dev/shm|x/etc|x/var|x/usr|x/usr/local|x/usr/local/etc|x/usr/etc) ;; \
*) echo " CHMOD(0751) $(DESTDIR)/@CONFPATH@" >&2 ; \
chmod 0751 "$(DESTDIR)/@CONFPATH@" \
|| exit ;; \
esac ; \
for F in hosts.conf.sample upsstats-single.html.sample upsstats.html.sample upsset.conf.sample ; do \
echo " CHMOD(0644) CGI: $(DESTDIR)/@CONFPATH@/$$F" >&2 ; \
chmod 0644 "$(DESTDIR)/@CONFPATH@/$$F" \
|| { if $(WITH_CGI) ; then exit 1 ; else true ; fi ; } ; \
done ; \
for F in nut.conf.sample ups.conf.sample upsd.conf.sample upsd.users.sample upsmon.conf.sample upssched.conf.sample ; do \
echo " CHMOD(0640) $(DESTDIR)/@CONFPATH@/$$F" >&2 ; \
chmod 0640 "$(DESTDIR)/@CONFPATH@/$$F" \
|| exit ; \
done ; \
else \
echo "$@: WARNING: Can not CHMOD created locations!" >&2 ; \
fi ; \
if (command -v chown) && test 0 -lt "`id -u '@RUN_AS_USER@'`" \
&& ( test 0 -lt "`getent group '@RUN_AS_GROUP@' | awk -F: '{print $$3}'`" || test 0 -lt "`id -g '@RUN_AS_GROUP@'`" ) \
; then \
echo " CHOWN(@RUN_AS_USER@:@RUN_AS_GROUP@) $(DESTDIR)/@STATEPATH@/upssched" >&2 ; \
chown "@RUN_AS_USER@:@RUN_AS_GROUP@" "$(DESTDIR)/@STATEPATH@/upssched" \
|| exit ; \
for D in "@STATEPATH@" "@PIDPATH@" "@ALTPIDPATH@" "@ALTSTATEPATH@" ; do \
case x"$$D" in \
x|x@*|x/run|x/var/run|x/tmp|x/var/tmp|x/dev/shm|x/etc|x/var|x/usr|x/usr/local|x/usr/local/etc|x/usr/etc) ;; \
*) echo " CHOWN(@RUN_AS_USER@:@RUN_AS_GROUP@) $(DESTDIR)/$$D" >&2 ; \
chown "@RUN_AS_USER@:@RUN_AS_GROUP@" "$(DESTDIR)/$$D" \
|| exit ;; \
esac ; \
done ; \
case x"@CONFPATH@" in \
x|x@*|x/run|x/var/run|x/tmp|x/var/tmp|x/dev/shm|x/etc|x/var|x/usr|x/usr/local|x/usr/local/etc|x/usr/etc) ;; \
*) echo " CHOWN(root:@RUN_AS_GROUP@) $(DESTDIR)/@CONFPATH@" >&2 ; \
chown "root:@RUN_AS_GROUP@" "$(DESTDIR)/@CONFPATH@" \
|| exit ;; \
esac ; \
for F in hosts.conf.sample upsstats-single.html.sample upsstats.html.sample upsset.conf.sample ; do \
echo " CHOWN(root:@RUN_AS_GROUP@) CGI: $(DESTDIR)/@CONFPATH@/$$F" >&2 ; \
chown "root:@RUN_AS_GROUP@" "$(DESTDIR)/@CONFPATH@/$$F" \
|| { if $(WITH_CGI) ; then exit 1 ; else true ; fi ; } ; \
done ; \
for F in nut.conf.sample ups.conf.sample upsd.conf.sample upsd.users.sample upsmon.conf.sample upssched.conf.sample ; do \
echo " CHOWN(root:@RUN_AS_GROUP@) $(DESTDIR)/@CONFPATH@/$$F" >&2 ; \
chown "root:@RUN_AS_GROUP@" "$(DESTDIR)/@CONFPATH@/$$F" \
|| exit ; \
done ; \
else \
echo "$@: WARNING: Can not CHOWN created locations!" >&2 ; \
fi ; \
if [ x"$(DESTDIR)" = x -o x"$(DESTDIR)" = x/ ] ; then \
if $(HAVE_SYSTEMD) ; then \
echo "$@: Activate default systemd layout, restart services:" >&2 ; \
if $(WITH_SYSTEMD_TMPFILES) ; then \
echo "$@: Apply systemd-tmpfiles presets" >&2 ; \
@SYSTEMD_TMPFILES_PROGRAM@ --create || exit ; \
fi ; \
echo "$@: Learn systemd definition changes" >&2 ; \
@SYSTEMD_SYSTEMCTL_PROGRAM@ daemon-reload || exit ; \
if $(WITH_SYSTEMD_PRESET) ; then \
echo "$@: Apply systemd enabled/disabled service presets" >&2 ; \
@SYSTEMD_SYSTEMCTL_PROGRAM@ preset-all || exit ; \
else \
echo "$@: Apply systemd enabled/disabled service defaults" >&2 ; \
@SYSTEMD_SYSTEMCTL_PROGRAM@ disable nut.target nut-driver.target nut-monitor nut-server nut-driver-enumerator.path nut-driver-enumerator.service || exit ; \
@SYSTEMD_SYSTEMCTL_PROGRAM@ enable nut.target nut-driver.target nut-monitor nut-server nut-driver-enumerator.path nut-driver-enumerator.service || exit ; \
fi ; \
echo "$@: Reconfigure nut-driver-enumerator (service instance wrapping)" >&2 ; \
@SYSTEMD_SYSTEMCTL_PROGRAM@ restart udev || true ; \
$(top_builddir)/scripts/upsdrvsvcctl/nut-driver-enumerator.sh --reconfigure || { RES=$$?; if [ $$RES != 42 ] ; then exit $$RES ; fi ; } ; \
echo "$@: Restart NUT services" >&2 ; \
@SYSTEMD_SYSTEMCTL_PROGRAM@ restart nut-driver-enumerator.service nut-monitor.service nut-server.service || exit ; \
fi ; \
fi ; \
echo "$@: finished" >&2 ; \
fi

# Clean the dist tarball and packages
MAINTAINERCLEANFILES_DISTBALL = nut-*.tar.gz
# HP-UX:
Expand Down
4 changes: 4 additions & 0 deletions NEWS.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -585,6 +585,10 @@ relocated into new `shutdown.default` INSTCMD definitions. [#2670]
- Introduced a simple experiment to expose NUT client readings as filesystem
objects via FUSE, in `scripts/fuse/execfuse-nut` now. [#2591]

- Introduced `make install-as-root` to create directories not directly
populated by `make install` and NUT build artifacts, apply permissions
and (on some platforms) restart services involved with NUT. [#1298]


Release notes for NUT 2.8.2 - what's new since 2.8.1
----------------------------------------------------
Expand Down
28 changes: 25 additions & 3 deletions configure.ac
Original file line number Diff line number Diff line change
Expand Up @@ -294,7 +294,20 @@ AS_IF([test x"${GETENT}" != x], [
],[
AS_IF([test x"${ID}" != x], [
PROBE_OS_USER="${ID} -u "
PROBE_OS_GROUP="${ID} -g "
AS_IF([test -r "/etc/groups"], [
dnl FIXME: For command prefix usage like used in this
dnl script, we might be better off defining a shell
dnl function and referring to it. Grep would catch
dnl also user names that have a group as secondary!
PROBE_OS_GROUP="cat /etc/groups | grep -w "
], [
dnl This shows groups of a USER with specified name!
dnl But to probe for cases where string names are
dnl same (e.g. "nut" or "ups") this might be good
dnl enough.
PROBE_OS_GROUP="${ID} -g "
])
AC_MSG_WARN([Can not PROPERLY check existence of group accounts on this system, but can try best-effort])
],[
AC_MSG_WARN([Can not check existence of user and group accounts on this system])
])
Expand All @@ -307,7 +320,7 @@ dnl certain other configure options (e.g. "in-place replacement")
RUN_AS_USER="nobody"
RUN_AS_GROUP="nobody"
AS_IF([test -n "`${PROBE_OS_GROUP} nogroup`" && ! test -n "`${PROBE_OS_GROUP} "${RUN_AS_GROUP}"`"],
[RUN_AS_GROUP="nogroup"]
[RUN_AS_GROUP="nogroup"]
)

dnl NOTE: NUT legacy default, keep as is for least surprise
Expand Down Expand Up @@ -463,7 +476,11 @@ AS_IF([test x"$nut_enable_inplace_runtime" = xyes -a x"${NUT_VERSION_DEPLOYED-}"
&& test x"${CONFIG_FLAGS_DEPLOYED}" != x \
|| CONFIG_FLAGS_DEPLOYED=""

NUT_VERSION_DEPLOYED="`"${DEPLOYED_TOOL}" -DV 2>&1 | grep 'configured with flags:' | head -1 | sed 's,^.*Network UPS Tools version \(.*\) configured with flags:.*$,\1,'`" \
dnl NOTE: Currntly NUT_VERSION_DEPLOYED is just informative (or a flag
dnl that we've "reentered" the configuration script), so we tolerate a
dnl better detailed string that is more than just a version, e.g.:
dnl 2.8.2.1829-1829-g8f8a4f417 (development iteration after 2.8.2) built with gcc (Debian 10.2.1-6) 10.2.1 20210110
NUT_VERSION_DEPLOYED="`"${DEPLOYED_TOOL}" -DV 2>&1 | grep 'configured with flags:' | head -1 | sed -e 's,^.*Network UPS Tools version \(.*\) configured with flags:.*$,\1,' -e 's, and *$,,'`" \
&& test x"${NUT_VERSION_DEPLOYED}" != x \
|| NUT_VERSION_DEPLOYED=""

Expand Down Expand Up @@ -4035,6 +4052,8 @@ dnl This option is only provided so that make distcheck can override it,
dnl otherwise we ask pkg-config whenever --with-systemdsystemunitdir is
dnl given

AC_PATH_PROG([SYSTEMD_SYSTEMCTL_PROGRAM], [systemctl], [/usr/bin/systemctl])

dnl Similarly for presets (list of svcs enabled/disabled by default)
AC_MSG_CHECKING(whether to install systemd preset files)
AC_ARG_WITH([systemdsystempresetdir],
Expand Down Expand Up @@ -4075,6 +4094,7 @@ if test -n "${systemdsystempresetdir}"; then
else
AC_MSG_RESULT(no)
fi
AM_CONDITIONAL([WITH_SYSTEMD_PRESET], [test x"${systemdsystempresetdir}" != "x"])

dnl Similarly for shutdown integration hooks
AC_MSG_CHECKING(whether to install systemd shutdown files)
Expand Down Expand Up @@ -4115,6 +4135,7 @@ if test -n "${systemdshutdowndir}"; then
else
AC_MSG_RESULT(no)
fi
AM_CONDITIONAL([WITH_SYSTEMD_SHUTDOWN], [test x"${systemdshutdowndir}" != "x"])

dnl Note: if (systemd-)tmpfiles tech is present, it can be useful even for
dnl daemons starting not as systemd units, to pre-create /var/run/nut etc.
Expand Down Expand Up @@ -4153,6 +4174,7 @@ if test -n "${systemdtmpfilesdir}"; then
else
AC_MSG_RESULT(no)
fi
AM_CONDITIONAL([WITH_SYSTEMD_TMPFILES], [test x"${systemdtmpfilesdir}" != "x"])

dnl What pathname would we embed into unit files ExecStartPre?
dnl TODO? Any need to make it a --with-... argument?
Expand Down
14 changes: 14 additions & 0 deletions docs/config-notes.txt
Original file line number Diff line number Diff line change
Expand Up @@ -327,6 +327,13 @@ the user you created in the preparation process.
The suggested configuration is to `chown` it to `root`, `chgrp` it to the
group you created, then make it readable by the group.

NOTE: If you installed NUT from source and used `make install-as-root`,
or if your distribution packaging did, the sample configuration files
would have the suggested ownership and permissions assigned, so if you
use e.g. `cp -pf upsd.users.sample upsd.users` (as `root`) to start out
with some annotated comments and adapt that to your deployment, the
copied files should also get the expected safe permissions.

chown root:nut upsd.conf upsd.users
chmod 0640 upsd.conf upsd.users

Expand Down Expand Up @@ -660,6 +667,13 @@ The recommended setting is to have it owned by `root:nut`, then make it
readable by the group and not by the world. This file contains passwords
that could be used by an attacker to start a shutdown, so keep it secure.

NOTE: If you installed NUT from source and used `make install-as-root`,
or if your distribution packaging did, the sample configuration files
would have the suggested ownership and permissions assigned, so if you
use e.g. `cp -pf upsmon.conf.sample upsmon.conf` (as `root`) to start out
with some annotated comments and adapt that to your deployment, the
copied files should also get the expected safe permissions.

chown root:nut upsmon.conf
chmod 0640 upsmon.conf

Expand Down
Loading
Loading