RPM build errors:Bad exit status from /var/tmp/rpm-tmp.32XJLX (%install) - bash

Im trying to create a simple rpm package on centos 6.5.. But i cannot finish it as its giving me errors.. I have already followed these two threads.. Bad exit status from /var/tmp/rpm-tmp.b1DgAt (%build) and Bad exit status from /var/tmp/rpm-tmp.ajKra4 (%prep) .. yet no luck...
I cannot figure out what i'm missing here.. please help me to fix this..
this is my
Name: test
Version: 1.0
Release: 1%{?dist}
Summary: A test package
Group: Testing
License: GPL
URL: http://www.yahoo.com
Source0: test-1.0.tar.gz
BuildRoot: %(mktemp -ud %{_tmppath}/%{name}-%{version}-%{release}-XXXXXX)
BuildRequires: /bin/rm, /bin/mkdir, /bin/cp
Requires: /bin/bash, /bin/date
%description
this is the test package build for rhche
%prep
%setup -q
%build
./configure
%install
rm -rf $RPM_BUILD_ROOT
make -p $RPM_BUILD_ROOT/usr/local/bin
cp myscriptdate $RPM_BUILD_ROOT/usr/local/bin
%clean
rm -rf $RPM_BUILD_ROOT
%files
%defattr(-,root,root,-)
%attr(0755,root,root)/usr/local/bin/myscriptdate
%changelog
* Thu Dec 09 2010 Forrest <forrest#redhat.com> 1.0-1
-Initial RPM
-Added /usr/local/bin/myscript
Source directory is /test1
[ara#catshit test1]$ pwd
/test1
[ara#catshit test1]$ ls -ls
total 12
4 drwxrwxrwx. 2 ara ara 4096 Dec 7 00:02 test-1.0
4 -rw-rw-r--. 1 ara ara 210 Dec 7 00:09 test-1.0.tar.gz
4 -rwxrwxrwx. 1 ara ara 742 Dec 7 00:17 test.spec
[ara#catshit test1]$
test-1.0 is compressed as test-1.0.tar.gz.
Inside test-1.0 I have script called myscriptdate which is having following simple code..
'#!/bin/bash
date
when i try rpmbuild -ba test.spec it gives me
# Not a target:
.f:
# Implicit rule search has not been done.
# Modification time never checked.
# File has not been updated.
# commands to execute (built-in):
$(LINK.f) $^ $(LOADLIBES) $(LDLIBS) -o $#
# Not a target:
.f.o:
# Implicit rule search has not been done.
# Modification time never checked.
# File has not been updated.
# commands to execute (built-in):
$(COMPILE.f) $(OUTPUT_OPTION) $<
# files hash-table stats:
# Load=70/1024=7%, Rehash=0, Collisions=278/1660=17%
# VPATH Search Paths
# No `vpath' search paths.
# No general (`VPATH' variable) search path.
# # of strings in strcache: 0
# # of strcache buffers: 0
# strcache size: total = 0 / max = 0 / min = 4096 / avg = 0
# strcache free: total = 0 / max = 0 / min = 4096 / avg = 0
# Finished Make data base on Sun Dec 7 00:51:01 2014
error: Bad exit status from /var/tmp/rpm-tmp.ZFlmeu (%install)
RPM build errors:
Bad exit status from /var/tmp/rpm-tmp.ZFlmeu (%install)
/var/tmp/rpm-tmp.ZFlmeu content is below
#!/bin/sh
RPM_SOURCE_DIR="/home/ara/rpmbuild/SOURCES"
RPM_BUILD_DIR="/home/ara/rpmbuild/BUILD"
RPM_OPT_FLAGS="-O2 -g"
RPM_ARCH="x86_64"
RPM_OS="linux"
export RPM_SOURCE_DIR RPM_BUILD_DIR RPM_OPT_FLAGS RPM_ARCH RPM_OS
RPM_DOC_DIR="/usr/share/doc"
export RPM_DOC_DIR
RPM_PACKAGE_NAME="test"
RPM_PACKAGE_VERSION="1.0"
RPM_PACKAGE_RELEASE="1.el6"
export RPM_PACKAGE_NAME RPM_PACKAGE_VERSION RPM_PACKAGE_RELEASE
LANG=C
export LANG
unset CDPATH DISPLAY ||:
RPM_BUILD_ROOT="/home/ara/rpmbuild/BUILDROOT/test-1.0-1.el6.x86_64"
export RPM_BUILD_ROOT
PKG_CONFIG_PATH="/usr/lib64/pkgconfig:/usr/share/pkgconfig"
export PKG_CONFIG_PATH
set -x
umask 022
cd "/home/ara/rpmbuild/BUILD"
cd 'test-1.0'
rm -rf $RPM_BUILD_ROOT
make -p $RPM_BUILD_ROOT/usr/local/bin
cp myscriptdate $RPM_BUILD_ROOT/usr/local/bin
/usr/lib/rpm/brp-compress
/usr/lib/rpm/brp-strip
/usr/lib/rpm/brp-strip-static-archive
/usr/lib/rpm/brp-strip-comment-note

The make -p $RPM_BUILD_ROOT/usr/local/bin line is your problem.
While not the problem you almost certainly don't want -p on that line. As it doesn't do anything useful for you during compilation and your rpm build process has no need to see the make database of rules.
The real problem is that you are telling make that you would like it to build the $RPM_BUILD_ROOT/usr/local/bin target which it is incredibly unlikely that make actually knows how to build (thus causing make to fail to build it and giving you an error). Removing the -p will help you see the actual error that make is spitting out as it will not also spit out the rule database stuff.
I think you meant mkdir -p there instead. (Which should be available as the %{__mkdir_p} macro.)

Related

make directory with bash builtin

I am writing bash script for Windows 7 and have limitation to bash.exe
mkdir -p does not work (command not found)
I am looking for any replacement/cheat with bash builtins. (the -p flag is not mandatory, could do this with a loop instead)
There is some idea to Transform a file into directory or some other nice hack only a expert will know. This question is not about how to fix a missing mkdir binary, but about reducing dependencies of (broken) core utils.
this are the available bash builtins:
& (( . : [ [[ alias bg bind break builtin caller case cd command compgen complete compopt continue coproc declare dirs disown echo enable eval exec exit export false fc fg for function getopts hash help history if jobs kill let local logout mapfile popd printf pushd pwd read readarray readonly return select set shift shopt source suspend test time times trap true type typeset ulimit umask unalias unset until wait while {
if not possible with bash builtins there are some external utils available. There is already one example which depends on cp
Create a new folder using bash without mkdir command
this is all i have:
bash blobpack blobunpack bzip2 cat chmod clear cpio cut dd dhtbsign dos2unix dumpimage elftool expr file find futility grep gzip hexdump kernel_dump loki_tool ls lz4 lzop mac2unix mboot md5sum mkbootimg mkimage mkmtkhdr mv printf pxa-mkbootimg pxa-unpackbootimg rkcrc rm sed stat sudo tail tar touch unix2dos unix2mac unpackbootimg unpackelf xz
Note: I have edited the question to clarify the needs.
If I'm reading the contents of that pastebin.com link correctly, this is not a true/complete cygwin installation.
That link shows the following (in a windows environment):
PATH = ... C:\Android\bash ... # this is not where cygwin is typically installed though, yeah, you could override the default installation directory
C:\Users\mint>bash # this is not how `cygwin/bash` is invoked
bash-4.1$
bash-4.1$ ls /cygdrive/c/Android/bash # full cygwin install does not throw everything under a single directory like this:
bash.exe ... snip ... mv.exe
At this point this doesn't appear to be an actual cygwin installation but rather some sort of reduced/incomplete/bastardized bash installation under the C:\Android\bash directory.
Where/How did OP 'install' the contents under the C:\Android\bash directory?
For comparison purposes (my windows machine):
# cygwin installation directory:
C:\cygwin64>dir
Volume in drive C is Windows7
Volume Serial Number is xxxx-yyyy
Directory of C:\cygwin64
11/06/2020 12:29 <DIR> .
11/06/2020 12:29 <DIR> ..
03/30/2021 16:08 <DIR> bin
05/25/2019 17:15 53,342 Cygwin-Terminal.ico
05/25/2019 18:46 95 Cygwin.2.bat
05/25/2019 17:15 88 Cygwin.bat
05/25/2019 17:15 157,097 Cygwin.ico
02/08/2021 13:01 <DIR> dev
02/04/2021 12:06 <DIR> etc
02/26/2021 16:35 <DIR> home
02/02/2021 11:34 <DIR> lib
07/12/2020 17:28 <DIR> sbin
11/06/2020 12:29 <DIR> srv
05/07/2021 07:46 <DIR> tmp
02/02/2021 11:34 <DIR> usr
05/25/2019 17:15 <DIR> var
6 File(s) 210,622 bytes
12 Dir(s) 20,305,154,048 bytes free
C:\cygwin64\bin>dir
Volume in drive C is Windows7
Volume Serial Number is xxxx-yyyy
Directory of C:\cygwin64\bin
03/30/2021 16:08 <DIR> .
03/30/2021 16:08 <DIR> ..
... snip ...
02/03/2017 14:40 37,395 base64.exe
02/03/2017 14:40 29,715 basename.exe
01/27/2017 14:13 739,859 bash.exe # bash binary
01/27/2017 14:13 7,291 bashbug
10/17/2014 17:00 81,949 bc.exe
... snip ...
12/20/2020 17:01 11,564 mintheme
02/03/2017 14:40 62,995 mkdir.exe # mkdir binary
02/03/2017 14:40 29,715 mkfifo.exe
08/22/2020 14:00 21,523 mkgroup.exe
... snip ...
2/19/2020 11:37 30 zstdless
2/03/2017 14:41 64,019 [.exe
1130 File(s) 541,740,761 bytes # 1100+ binaries in this directory
2 Dir(s) 20,305,154,048 bytes free
# example cygwin session startup
C:\cygwin64\bin\mintty.exe -i /Cygwin-Terminal.ico -
# user has option to startup a few different tty's;
# actual OS is determined from /etc/passwd entry (/usr/bin/bash in my case)
At this point if OP wants to run cygwin/bash then I'd suggest installing an actual cygwin environment (see cygwin.org ), making sure to also install the bash package.
As for how to simulate mkdir with ... whatever is installed under C:\Android\bash ... shrug ... have the originator pull more of the binaries (eg, mkdir.exe) from a complete cygwin/bash installation?
----------------------- previous answer (before reviewing the contents of the pastebin.com link)
I'm wondering if this could be an issue of an incomplete/corrupted cygwin/bash installation or an invalid $PATH ... ?
From my cygwin environment:
$ bash --version
GNU bash, version 4.4.12(3)-release (x86_64-unknown-cygwin)
$ which mkdir
/usr/bin/mkdir
$ command -v mkdir
/usr/bin/mkdir
$ mkdir --version
mkdir (GNU coreutils) 8.26
Packaged by Cygwin (8.26-2)
Does /usr/bin/mkdir exist?
What is returned when running find / -name mkdir*?
If you can find mkdir(.exe) then the next check would be for the location/path also being defined in $PATH ...
This trick can be helpful to run Windows md shell builtin from within bash script
echo -e 'md %*\r' > mkdir.bat
./mkdir.bat test

rpmbuild exiting with error: File not found

I'm trying to build my first RPM package and struggling with the rpmbuild process.
This is my environment I have to deal with:
cat /home/rpmadm/.rpmmacros
%_topdir /export/standardbuild
%_tmppath /export/standardbuild/tmp
%_sourcedir /export/standardbuild/SOURCES
%_rpmdir /export/standardbuild/RPMS
%_srcrpmdir /export/standardbuild/SRPMS
%_builddir /export/standardbuild/COMP_BUILDS/%{name}
My Makefile looks like this:
packagename = metricconf
%_sourcedir = /export/standardbuild/SOURCES
# version number of package: make sure you also update the version
# number in the spec file
version = 1.0
all:
#echo "usage: make dist | package"
install:
if [ ! -d $(DESTDIR)/tmp/$(packagename) ]; \
then \
mkdir -p $(DESTDIR)/tmp/$(packagename); \
fi
cp mb_system_betrieb.yml $(DESTDIR)/tmp/$(packagename)/mb_system_betrieb.yml
cp metricbeat $(DESTDIR)/tmp/$(packagename)/metricbeat
cp metricbeat.yml $(DESTDIR)/tmp/$(packagename)/metricbeat.yml
dist:
tar cvf $(packagename)-$(version).tar ../$(packagename)-$(version)
gzip $(packagename)-$(version).tar
cp $(packagename)-$(version).tar.gz $(%_sourcedir) && rm $(packagename)-$(version).tar.gz
package: rpm
rpm:
rpmbuild -ba $(packagename).spec
rm -rf $(packagename)-$(version).tar
And this is my .spec file:
Summary: configures Metricbeat for AIX
Name: metricconf
Version: 1.0
Release: 0
Vendor: Comp
Source: metricconf-1.0.tar.gz
BuildRoot: %{_builddir}/%{name}-{version}
Requires: metricbeat
%description
metricconf prepares AIX for metricbeat
%prep
%setup -c
%build
%install
%files
%defattr(644,root,system)
/tmp/metricbeat.yml
/tmp/mb_system_betrieb.yml
/tmp/metricbeat
make dist works well and the .tar.gz file will be created correctly.
But the make rpm command fails every time with following error:
make rpm
rpmbuild -ba metricconf.spec
Executing(%prep): /bin/sh -e /export/standardbuild/tmp/rpm-tmp.cIlqQa
+ umask 022
+ cd /export/standardbuild/COMP_BUILDS/metricconf
+ cd /export/standardbuild/COMP_BUILDS/metricconf
+ rm -rf metricconf-1.0
+ /usr/bin/mkdir -p metricconf-1.0
+ cd metricconf-1.0
+ /bin/gzip -dc /export/standardbuild/SOURCES/metricconf-1.0.tar.gz
+ /bin/tar -xvvof -
x ../COOPmetricbeat-1.0
x ../COOPmetricbeat-1.0/metricconf.spec, 2289 bytes, 5 tape blocks
x ../COOPmetricbeat-1.0/ChangeLog, 135 bytes, 1 tape blocks
x ../COOPmetricbeat-1.0/Makefile, 885 bytes, 2 tape blocks
x ../COOPmetricbeat-1.0/README, 74 bytes, 1 tape blocks
x ../COOPmetricbeat-1.0/mb_system_betrieb.yml, 1161 bytes, 3 tape blocks
x ../COOPmetricbeat-1.0/metricbeat, 1552 bytes, 4 tape blocks
x ../COOPmetricbeat-1.0/metricbeat.yml, 1240 bytes, 3 tape blocks
+ STATUS=0
+ [ 0 -ne 0 ]
+ /bin/chmod -Rf a+rX,u+w,g-w,o-w .
+ exit 0
Executing(%build): /bin/sh -e /export/standardbuild/tmp/rpm-tmp.dalqQb
+ umask 022
+ cd /export/standardbuild/COMP_BUILDS/metricconf
+ cd COOPmetricbeat-1.0
+ exit 0
Executing(%install): /bin/sh -e /export/standardbuild/tmp/rpm-tmp.delqQc
+ umask 022
+ cd /export/standardbuild/COMP_BUILDS/metricconf
+ cd metricconf-1.0
+ exit 0
Processing files: metricconf-1.0-0.ppc
error: File not found: /export/standardbuild/tmp/metricconf-1.0-0.ppc/tmp/metricbeat.yml
error: File not found: /export/standardbuild/tmp/metricconf-1.0-0.ppc/tmp/mb_system_betrieb.yml
error: File not found: /export/standardbuild/tmp/metricconf-1.0-0.ppc/tmp/metricbeat
RPM build errors:
File not found: /export/standardbuild/tmp/metricconf-1.0-0.ppc/tmp/metricbeat.yml
File not found: /export/standardbuild/tmp/metricconf-1.0-0.ppc/tmp/mb_system_betrieb.yml
File not found: /export/standardbuild/tmp/metricconf-1.0-0.ppc/tmp/metricbeat
make: 1254-004 The error code from the last command is 1.## Heading ##
Please, can anyone explain to me why rpmbuild is looking in "/export/standardbuild/tmp/metricconf-1.0-0.ppc" for the files and not in "/export/standardbuild/COMP_BUILDS/metricconf/metricconf-1.0" ???
I read a lot about building rpms especially at Fedora's doc pages, but it doesn't matter what I change in the Makefile or .spec file, the error remains.
Your %build and %install phases are both empty, so it's not doing anything. All you have is %prep which is untarring it into a temporary staging area.
Look around for examples, e.g. if you are using autoconf you probably want %configure.
ETA: It also looks like you are trying to put your final files into /tmp on the target machine, which won't work because they will disappear after a reboot. %files should list the files to be installed on the target without any leading temporary paths.

How to run and interact with a script from within an RPM?

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.
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:
%post section is executed under root, so sudo is not needed.
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).

Is there an elegant way to control permissions for directories created by "install -D"?

I am using [/usr/bin/]install in a Makefile to copy some binaries into my $HOME directory. My umask is set to 700.
The problem is that I am using install -D -m 700 to install the binaries and the parent directory is created with permissions of 755 and not 700:
$ umask
077
$ ls
$ touch hello
$ ls -l
total 0
-rw------- 1 emuso emuso 0 Apr 5 13:15 hello
$ install -D -m 700 hello $PWD/this/is/hello
$ ls -ld this
drwxr-xr-x 3 emuso emuso 4096 Apr 5 13:17 this
$ ls -lR this
this:
total 4
drwxr-xr-x 2 emuso emuso 4096 Apr 5 13:17 is
this/is:
total 0
-rwx------ 1 emuso emuso 0 Apr 5 13:17 hello
I want that the directories this and is get permissions 700 instead of 755.
Solutions that come to my mind are:
using install -d -m 700 to create the directory structure by hand.
using chmod to fix permissions manually.
The major drawback for the first solution is that I have a directory structure, which I would have to travel and create by hand.
So my question is: Is there an elegant way to control permissions for directories created by "install -D"?
What you want to achieve does not seem possible with a single invocation to install only, so you might have to resort to a combination of mkdir and install. Depending on your exact situation, you might be able to take advantage of a canned recipe, using something like this:
define einstall
test -d "$(dir $#)" || mkdir -p "$(dir $#)"
install -m 700 $< $#
endef
some/new/test/hello: hello
$(einstall)
If you plan to play around with canned recipes with make v3.81 or older, please make sure to read this answer to Why GNU Make canned recipe doesn't work?

Suppress make rule error output

I have an rule that creates a directory
bin:
-mkdir $#
However after the first time the directory has been generated, I receive this output:
mkdir bin
mkdir: cannot create directory `bin': File exists
make: [bin] Error 1 (ignored)
Is there some way I can only run the rule if the directory doesn't exist, or suppress the output when the directory already exists?
Another way to suppress the make: error ... (ignored) output is to append || true to a command that could fail. Example with grep that checks for errors in a LaTeX log file:
undefined:
#grep -i undefined *.log || true
Without the || true, make complains when grep fails to find any matches.
This works for all commands, not just mkdir; that's why I added this answer.
The error is ignored already by the leading '-' on the command line. If you really want to lose the error messages from mkdir, use I/O redirection:
bin:
-mkdir bin 2> /dev/null
You will still get the 'ignored' warning from make, though, so it might be better to use the option to mkdir that doesn't cause it to fail when the target already exists, which is the -p option:
MKDIR_P = mkdir -p
bin:
${MKDIR_P} $#
The -p option actually creates all the directories that are missing on the given paths, so it can generate a a number of directories in one invocation, but a side-effect is that it does not generate an error for already existing directories. This does assume a POSIX-ish implementation of mkdir; older machines may not support it (though it has been standard for a long time now).
The traditional way to handle directory creation is to use a stamp file that is depended on and creates the dir as a side effect. Remove the stamp file when making distclean or whatever your "really clean" target is:
bin/.dirstamp:
mkdir -p $(DIRS)
touch $#
bin/foo: bin/.dirstamp
$(MKFOO) -o $#
distclean:
rm -rf bin
The reason for this is as follows: whenever a file in bin is created/removed, the mtime of the containing directory is updated. If a target depends on bin, then the next time make runs, it will then recreate files that it doesn't need to.
Well I ended up with this construct, maybe someone will find it useful or can comment on it:
BINDIR = .
TMPDIR = tmp
OUTDIRS = $(BINDIR) $(TMPDIR)
$(OUTDIRS):
#test -d $# || mkdir $#
You rule should not be executed unless its target does not exists or is out of date because of its dependencies. In other words, you should never encounter this error.
[Example Added]
[max#truth tmp]$ ls -la
total 20
drwxr-xr-x. 2 max users 4096 Aug 14 21:11 .
drwx------. 80 max max 4096 Aug 14 18:25 ..
-rw-rw-r-- 1 max max 38 Aug 14 21:11 Makefile
[max#truth tmp]$ cat Makefile
.PHONY: all
all: bin
bin:
mkdir $#
[max#truth tmp]$ make
mkdir bin
[max#truth tmp]$ ls -la
total 24
drwxr-xr-x. 3 max users 4096 Aug 14 21:11 .
drwx------. 80 max max 4096 Aug 14 18:25 ..
drwxrwxr-x 2 max max 4096 Aug 14 21:11 bin
-rw-rw-r-- 1 max max 38 Aug 14 21:11 Makefile
[max#truth tmp]$ make
make: Nothing to be done for `all'.
[max#truth tmp]$ make
make: Nothing to be done for `all'.
Does your folder depend on anything? Is your folder a phony target?
Make assumes the first target is the default target. If that is your complete makefile, then it must be always trying to remake the default target, which is bin. Insert the following lines to the top of your makefile:
all: bin
.PHONY: all

Resources