linuxmkdircheckinstall

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


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 --maintainer=me@example.com --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.


Solution

  • 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
    ....