Why isn't mkdir -p working right in a script called by checkinstall?
Asked Answered
O

3

10

I'm trying to compile Quarter and package it using checkinstall.

If I do the standard ./configure && make && sudo make install, things go fine.

$ wget http://ftp.coin3d.org/coin/src/all/Quarter-1.0.0.tar.gz
$ tar xzf Quarter-1.0.0.tar.gz
$ cd Quarter-1.0.0
$ ./configure
$ make
$ sudo make install

But when I use checkinstall, it fails on a mkdir -p that should work perfectly fine. The way it fails is exactly how it would as if the -p option weren't given. This is the checkinstall command line I'm using:

$ checkinstall -D -y --install=no --pkgname=libquarter --pkgversion=1.0.0 \
  --arch=i386 --pkglicense=GPL [email protected] --reset-uids=yes

This is the failure:

....
/bin/bash ../../../cfg/mkinstalldirs /usr/local/include/Quarter/devices
mkdir -p -- /usr/local/include/Quarter/devices
mkdir: cannot create directory `/usr/local/include/Quarter': No such file or directory
make[4]: *** [install-libdevicesincHEADERS] Error 1
....

This is the relevant part of the script:

$ cat cfg/mkinstalldirs
....
case $dirmode in
  '')
    if mkdir -p -- . 2>/dev/null; then
      echo "mkdir -p -- $*"
      exec mkdir -p -- "$@"
    fi
    ;;
....

I don't understand why that exec is there -- doesn't that guarantee that the remainder of the script (after the esac) will never execute? (If the if test passes, then the script assumes mkdir -p works correctly, so once it does the real mkdir -p it can quit; otherwise the remainder of the script implements proper mkdir -p behavior.) I also don't understand why it uses "$*" in the echo and "$@" in the next line, but it doesn't seem to matter -- they're both the same thing since this script is being called with just one argument. (Tom explained in comment.)

If I add two lines between echo and exec that does mkdir -p -- "$@" and then echo "Now doing the exec mkdir..." then it works like this -- better, but still bewildering:

/bin/bash ../../../cfg/mkinstalldirs /usr/local/include/Quarter/devices
mkdir -p -- /usr/local/include/Quarter/devices
mkdir: cannot create directory `/usr/local/include/Quarter': No such file or directory
Now doing the exec mkdir...
 /usr/bin/install -c -m 644 InputDevice.h /usr/local/include/Quarter/devices/InputDevice.h
.... finishes successfully!

Now, the fact that doing the mkdir line twice made it work tells me it's not a permissions issue (beside, that would generate a different diagnostic from mkdir, and this is being run as sudo, and it's actually working in /var/tmp/... not the real /usr/local/...). I think what's happening is that the first mkdir invocation (the one I added) is actually creating just the Quarter directory and bailing out, and then when the second mkdir runs, it's able to create the devices subdirectory, because the Quarter directory is already there. But why would mkdir work that way???

My workaround is to patch that mkinstalldirs script somehow, but I'm really curious why this is breaking!

This is a Ubuntu 10.10 guest running in VirtualBox on Win7, checkinstall version 1.6.2 installed thru apt-get.


EDIT: I did some testing to see what works and what fails in this environment...

mkdir -p /foo works correctly
mkdir -p /foo && mkdir -p /foo/bar works correctly
mkdir -p foo/bar works correctly
mkdir /foo/bar failed as expected (correct)
mkdir foo/bar failed as expected (correct)
mkdir -p /foo/bar fails

Weird that -p works for relative pathnames but not for absolute pathnames. Or maybe the correct distinction is that -p works outside of the "chroot" tree (if it's even really using chroot) but not within it.

I also verified that despite the failure, it is able to create the first directory level.

Still a mystery.

Oscillograph answered 11/2, 2011 at 23:34 Comment(7)
What do you mean by "it's actually working in /tmp/... not the real /usr/local/..."? Chroot?Jarl
FWIW, i imagine the use of $* in the echo is so that echo is given one parameter containing the whole command line, rather than the N parameters, one for each argument, it would get if $@ was used. It's a very minor neatness and efficiency thing. It does look weird sitting right next to a use of $@, though.Jarl
@Tom, that would be my guess. I need to sudo for it to work at all, but it's not doing a real install (which is what I wanted since I just want to create the package). Not sure why I have to sudo at all, but I can live with it. And thanks for the explanation of $* vs. $@!Oscillograph
@tom there's a difference between "$*" and "$@"Wealthy
@Tom, I'm reading thru the checkinstall source, looks like it's intercepting calls like mkdir() etc. and replacing them with its own versions. Must be a bug in there somewhere. So it's probably not using chroot.Oscillograph
This is a bug.Sombrous
Just stumbled on this mkdir -p absolute path limitation. Quite annoying. But in your last comment you say "Despite the failure, it is able to create the first directory level" but that isn't happening for me. If that were the case then you could just run the same command a few times until it piecemealed each directory step, but that isn't happening.Streusel
O
2

mkdir -p isn't working like it should because it's a checkinstall version of mkdir, not the "true" mkdir. Must be some bug in checkinstall that makes it work a bit differently.

This patch works around the bug:

./configure
sed -i 's/if mkdir .*-p --.*; then/if false; then ## &/' cfg/mkinstalldirs
....
Oscillograph answered 12/2, 2011 at 11:59 Comment(0)
C
23

Using

checkinstall --fstrans=no

should fix this. Or

Set "TRANSLATE=0"

in /etc/checkinstallrc and try again.

Coff answered 26/10, 2011 at 9:32 Comment(2)
It was fixed it checkinstall git long time ago but its still not in release version. Anyway, this is great tip.Petronius
Obviously this doesn't work if you need file system translation, i.e. if you don't have root access. Not so much a fix but a very limiting workaround.Jocosity
O
2

mkdir -p isn't working like it should because it's a checkinstall version of mkdir, not the "true" mkdir. Must be some bug in checkinstall that makes it work a bit differently.

This patch works around the bug:

./configure
sed -i 's/if mkdir .*-p --.*; then/if false; then ## &/' cfg/mkinstalldirs
....
Oscillograph answered 12/2, 2011 at 11:59 Comment(0)
W
0
sed -i -e 's/TRANSLATE=1/TRANSLATE=0/g' /etc/checkinstallrc
Withe answered 2/11, 2014 at 13:47 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.