How to run and interact with a script from within

2019-09-05 14:37发布

问题:

I'm building an RPM which needs to run a bash script as root.

The %install stanza of the spec file is:

%install

cp %{SOURCE1} %{SOURCE2} %{_tmppath}/%{name}-%{version}-%{release}
cd %{_tmppath}/%{name}-%{version}-%{release}
chmod u+x %{installscript}
sudo ./%{installscript}

Where %{installscript} is the script that runs as root with sudo.

rpmbuild executes %{installscript} and creates the RPM (without problems).

However, when I install the RPM:

$ sudo rpm -Uvh $rpmpath
Preparing...                ########################################### [100%]
   1:tty-cap ########################################### [100%]
$

The %{installscript} script is not executed.

I tried to change the spec file by moving the script invocation to a %post stanza:

%install

cp %{SOURCE1} %{SOURCE2} %{_tmppath}/%{name}-%{version}-%{release}
cd %{_tmppath}/%{name}-%{version}-%{release}

%post

chmod u+x %{installscript}
sudo ./%{installscript}

But the %post doesn't seem to do anything.

How can I pack an RPM that will execute a script when installed?


Edit 1:

After reviewing the helpful comments below, here's a spec file with a %post stanza that actually gets executed during the RPM installation.
However, the script %{installscript} does not interact with the user (as it does when run from the shell), but seems to accept all its defaults without user interaction.
What should I change so that the script will interact with the rpm command user?

$ cat ~/RPMBUILD/SPECS/demo.spec
#
# %_topdir and %_tmppath are defined in  ~/.rpmmacros

%define name tty-cap
%define version 5.2
%define release 1
%define buildroot %{_tmppath}/%{name}-%{version}-%{release}

%define tarversion tty-5.2.0-00-70270
%define tarfile %{tarversion}.tar
%define installscript tty.install.sh

Name:           %{name}
Version:        %{version}
Release:        %{release}
BuildArch:      noarch
Summary:        Bla
License:        Proprietary
Source1:        %{installscript}
Source2:        tty-5.2.0-00-70270.tar
Prefix:         /opt/Intellinx/TTYCapture
BuildRoot:      %{_builddir}/%{name}-root

%description
Demonstration RPM

%prep

%build

%install

cp %{SOURCE1} %{SOURCE2} %{_tmppath}/%{name}-%{version}-%{release}
cd %{_tmppath}/%{name}-%{version}-%{release}

%clean
[ ${RPM_BUILD_ROOT} != "/" ] && rm -rf ${RPM_BUILD_ROOT}

%post
echo ">>> Inside post <<<"
chmod u+x %{installscript}
./%{installscript}

%files

%define tmp /
%{tmp}/%{tarfile}
%{tmp}/%{installscript}

$ rpmbuild -v -bb  ~/RPMBUILD/SPECS/demo.spec
Executing(%prep): /bin/sh -e /home/ronbarak/RPMBUILD/tmp/rpm-tmp.oEOM10
+ umask 022
+ cd /home/ronbarak/RPMBUILD/BUILD
+ LANG=C
+ export LANG
+ unset DISPLAY
+ exit 0
Executing(%build): /bin/sh -e /home/ronbarak/RPMBUILD/tmp/rpm-tmp.qQFuTA
+ umask 022
+ cd /home/ronbarak/RPMBUILD/BUILD
+ LANG=C
+ export LANG
+ unset DISPLAY
+ exit 0
Executing(%install): /bin/sh -e /home/ronbarak/RPMBUILD/tmp/rpm-tmp.8rTMLa
+ umask 022
+ cd /home/ronbarak/RPMBUILD/BUILD
+ '[' /home/ronbarak/RPMBUILD/tmp/tty-cap-5.2-1 '!=' / ']'
+ rm -rf /home/ronbarak/RPMBUILD/tmp/tty-cap-5.2-1
++ dirname /home/ronbarak/RPMBUILD/tmp/tty-cap-5.2-1
+ mkdir -p /home/ronbarak/RPMBUILD/tmp
+ mkdir /home/ronbarak/RPMBUILD/tmp/tty-cap-5.2-1
+ LANG=C
+ export LANG
+ unset DISPLAY
+ cp /home/ronbarak/RPMBUILD/SOURCES/tty.install.sh /home/ronbarak/RPMBUILD/SOURCES/tty-5.2.0-00-70270.tar /home/ronbarak/RPMBUILD/tmp/tty-cap-5.2-1
+ cd /home/ronbarak/RPMBUILD/tmp/tty-cap-5.2-1
+ /usr/lib/rpm/check-buildroot
+ /usr/lib/rpm/redhat/brp-compress
+ /usr/lib/rpm/redhat/brp-strip /usr/bin/strip
+ /usr/lib/rpm/redhat/brp-strip-static-archive /usr/bin/strip
+ /usr/lib/rpm/redhat/brp-strip-comment-note /usr/bin/strip /usr/bin/objdump
+ /usr/lib/rpm/brp-python-bytecompile
+ /usr/lib/rpm/redhat/brp-python-hardlink
+ /usr/lib/rpm/redhat/brp-java-repack-jars
Processing files: tty-cap-5.2-1.noarch
Requires(interp): /bin/sh
Requires(rpmlib): rpmlib(CompressedFileNames) <= 3.0.4-1 rpmlib(FileDigests) <= 4.6.0-1 rpmlib(PayloadFilesHavePrefix) <= 4.0-1
Requires(post): /bin/sh
Checking for unpackaged file(s): /usr/lib/rpm/check-files /home/ronbarak/RPMBUILD/tmp/tty-cap-5.2-1
Wrote: /home/ronbarak/RPMBUILD/RPMS/noarch/tty-cap-5.2-1.noarch.rpm
Executing(%clean): /bin/sh -e /home/ronbarak/RPMBUILD/tmp/rpm-tmp.Yag9bm
+ umask 022
+ cd /home/ronbarak/RPMBUILD/BUILD
+ '[' /home/ronbarak/RPMBUILD/tmp/tty-cap-5.2-1 '!=' / ']'
+ rm -rf /home/ronbarak/RPMBUILD/tmp/tty-cap-5.2-1
+ exit 0

$ sudo rpm -Uvh /home/ronbarak/RPMBUILD/RPMS/noarch/tty-cap-5.2-1.noarch.rpm
Preparing...                ########################################### [100%]
   1:tty-cap                ########################################### [100%]
>>> Inside post <<<

###### Starting tty capturing installation ######


Specify installation directory full path [/opt/Intellinx/TTYCapture]:
/opt/Intellinx/TTYCapture already exists. continue installation? (y/n) [y]
Extracting archive tty-5*.* ...

Please specify TTY sensor owner user [ronbarak]:
TTY sensor will be accessible by user 'ronbarak' in group 'ronbarak'

Specify sensor working directory full path [/opt/Intellinx/TTYCapture/work]:

Specify sensor listening port [1024-65000] [8888]:

Do you want to register the sensor service? (y/n) [n]
Server gxttySensorService is not register as a daemon

Executing default user shell (y/n) [y]

TTY capturing has been installed successfully.

回答1:

You are mixing several concepts here. So let make step back.

In %prep section you should unpack your %{SOURCE0} and apply patches if any. This usually do

%setup -q

However if you want you can extract it manually. For more info about this macro see http://www.rpm.org/max-rpm/s1-rpm-inside-macros.html

In %build section you usually compile source into binaries. Likely empty if you use interpreted language or your tar contains already compiled binaries.

In %install section you should copy the files into %{buildroot} and create there structure which will land in package. E.g. %{buildroot}/etc/yourconfig, %{buildroot}/usr/bin/yourcommand etc. You can run there any script you want, but keep in mind that it is run only in build time. I.e. only on your machine (or build system). This is intended for creating files which are automatically generated (e.g. documentation of libraries from source code).

Then you have section %post which is run on user machine after the package was installed. And all files are installed in final path. Not in buildroot. At the beginning you are changed to / so you need to specify full path on that user machine.

So in your case it should be probably look like:

%install
mkdir -p %{buildroot}%{_bindir}
cp -a %{installscript} %{buildroot}%{_bindir}/
chmod a+x %{buildroot}%{_bindir}/%{installscript}

%files
%{_bindir}/%{installscript}

%post
%{_bindir}%{installscript}

Sever notes:

  1. %post section is executed under root, so sudo is not needed.

  2. Running interactive script is strongly discouraged. RPM was designed as non-interactive and every utility around assume no interaction during package installation (e.g. PackageKit, Spacewalk etc.). So sooner then later you will get some compains. It is much safer to say user to run some command after installation manually (or automate it using Ansible or Puppet).