bug-automake
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: make install using "-j"


From: Ralf Wildenhues
Subject: Re: make install using "-j"
Date: Wed, 21 Jun 2006 21:32:16 +0200
User-agent: Mutt/1.5.11+cvs20060403

[ http://lists.gnu.org/archive/html/bug-automake/2006-06/msg00018.html ]

Hello David, everyone,

Summary of this post:

1) I think I can reproduce the bug you reported with a small test, but
   would like confirmation that this is indeed the same issue.
2) IMHO the bug has since been fixed "accidentally" in install-sh.
3) Found an unrelated bug in HP-UX mkdir that requires a workaround in
   install-sh to satisfy Automake's requirements.

* David Everly wrote on Tue, Jun 20, 2006 at 09:37:56PM CEST:
> 
[...]
>mkdir: cannot create /tmp/am-dc-7581//home/deverly: File exists
>mkdir: cannot create /tmp/am-dc-7581//home/deverly: File exists
>mkdir: cannot create /tmp/am-dc-7581//home/deverly/trunk-nightly: File exists
>mkdir: cannot create /tmp/am-dc-7581//home/deverly/trunk-nightly: File exists

0) Above output isn't enough information.  It is important to also post
the command that 'make' issued that caused the failures, and, in this
case, also a couple of commands that happened earlier.  Please do so to
confirm the following analysis.

1) An interesting and tricky issue.  I can reproduce the failure on:

> ia64-hp-hpux11.23

with this version of the script (from Automake-1.9.6):

> ./install-sh 2005-05-14.22

with this example package:

- snip -
cat >configure.ac <<EOF
AC_INIT([j4], [2], [devnull])
AM_INIT_AUTOMAKE([foreign])
AC_CONFIG_FILES([Makefile])
AC_OUTPUT
EOF
cat >Makefile.am <<EOF
# the subdir names are harmless and not relevant for the first test.
dist_sysconf_DATA = \
        a/b/c/d/e/file1
dist_pkgdata_DATA = \
        a/b/c/d/e/file2
dist_data_DATA = \
        a/b/c/d/e/file3 \
        a/b/c/d/e/file4
EOF
mkdir -p a/b/c/d/e
cd a/b/c/d/e
touch file1 file2 file3 file4
cd -
autoreconf -vi
./configure
make -j4 distcheck
- snip -

The error output looks like this for me:

[...]
| gmake[2]: Entering directory `/home/rwild/j4/build/j4-2/_build'
| test -z "/home/rwild/j4/build/j4-2/_inst/etc" || 
/home/rwild/j4/build/j4-2/install-sh -d 
"/tmp/am-dc-27562//home/rwild/j4/build/j4-2/_inst/etc"
| test -z "/home/rwild/j4/build/j4-2/_inst/share/j4" || 
/home/rwild/j4/build/j4-2/install-sh -d 
"/tmp/am-dc-27562//home/rwild/j4/build/j4-2/_inst/share/j4"
| test -z "/home/rwild/j4/build/j4-2/_inst/share" || 
/home/rwild/j4/build/j4-2/install-sh -d 
"/tmp/am-dc-27562//home/rwild/j4/build/j4-2/_inst/share"
| mkdir: cannot create /tmp/am-dc-27562//home/rwild/j4: File exists
| mkdir: cannot create /tmp/am-dc-27562//home/rwild/j4/build/j4-2/_inst: File 
exists
| mkdir: cannot create /tmp/am-dc-27562//home/rwild/j4/build/j4-2/_inst/share: 
File exists
| gmake[2]: *** [install-dist_dataDATA] Error 1

The actual error is not immediately obvious from this output.  The first
two `File exists' are harmless: for all intermediate directories,
install-sh calls plain mkdir in a loop calling
        $mkdirprog "$pathcomp"
        # mkdir can fail with a `File exist' error in case several
        # install-sh are creating the directory concurrently.  This
        # is OK.
        test -d "$pathcomp" || exit

but this does not cause the exit failure (as the following `test -d'
succeeds).  The real issue is that the final mkdir executed by the third
`install-sh -d' in above sequence happens in this code snippet:

   if test -n "$dir_arg"; then
     $doit $mkdircmd "$dst" \
       && { test -z "$chowncmd" || $doit $chowncmd "$dst"; } \
       && { test -z "$chgrpcmd" || $doit $chgrpcmd "$dst"; } \
       && { test -z "$stripcmd" || $doit $stripcmd "$dst"; } \
       && { test -z "$chmodcmd" || $doit $chmodcmd "$dst"; }
   else
     #...
   fi || { (exit 1); exit 1; }

and it fails, thus the script exits 1.  So, the race is:

 (a) exec `install-sh -d .../_inst/share'             -> process A
 (b) exec `install-sh -d .../_inst/share/j4'          -> process B
 (c) A tests whether the directory already exists     -> no.
 (d) B tests whether the directory already exists     -> no.
 (e) for each intermediate directory up to `_inst',
     - A or B succeed in the mkdir
     - the respective other one fails, thus the error output,
       but neither sets the exit status (which is correct).
 (f) B wins the race creating the component `share'
 (g) A fails to mkdir its final component `share'     -> failure.
 (h) B succeeds in creating its final component `j4'  -> success. 
 
So actually, the short-cut test (c), (d) early in install-sh only hides
this error from (g) in the case of non-parallel executions.


2) AFAICS, this problem has been fixed in the current install-sh
(instead of the one that ships with Automake-1.9.6).
David, could you try the script?  You can get it with

  cvs -d :pserver:anoncvs:address@hidden:/cvs/automake \
      co -p automake/lib/install-sh > install-sh
 
It seems the patch that fixed this was this one by Paul Eggert:
http://lists.gnu.org/archive/html/automake-patches/2005-09/msg00003.html
as it removes the special-casing of the `mkdir' for the last component
of `install-sh -d'.  However, the ChangeLog entry is way too terse to
make this obvious; a fact which, by the way, has been noted already in
http://lists.gnu.org/archive/html/automake-patches/2005-07/msg00029.html


* David Everly wrote on Tue, Jun 20, 2006 at 10:37:08PM CEST:
> One more thing I tried just now, which seems to work...I compiled and
> installed coreutils 5.96 and autoconf/automake seems to like that
> version of mkdir enough to not use the wrapper, and so far, it seems
> to be working in a parallel build.

OK.  But install-sh is intended to perform this function portably.

So I'd like you to try the newer script on your package, and see if
you can get it to fail as well.  Thanks.



3) Another issue I just observed: even with the current install-sh,
there is a different failure: non-parallel, but with nobase_ files
(this is where Automake always uses install-sh, and assumes that
  install-sh -m 644 file /path/to/some/where/file
will create intermediate directories).

To see this, let's change the example package from (1) like this:

sed s/2/3/ configure.ac >t      # that was version 3 of my test
mv t configure.ac
sed "s/^dist_/nobase_&/" Makefile.am >t
mv t Makefile.am
autoreconf -vi
./configure
make distcheck

| gmake[2]: Entering directory `/tmp/build/j4-3/_build'
| test -z "/tmp/build/j4-3/_inst/etc" || /tmp/build/j4-3/install-sh -d 
"/tmp/build/j4-3/_inst/etc"
|  /tmp/build/j4-3/install-sh -c -m 644 '../a/b/c/d/e/file1' 
'/tmp/build/j4-3/_inst/etc/a/b/c/d/e/file1'
| mkdir: cannot create /tmp/build/j4-3/_inst/etc/a/b: Permission denied

This is due to a bug in HP-UX 11.23 mkdir that install-sh doesn't detect
yet.  With a umask of 002,
$ mkdir -m u=rwx,g=rx,o=rx -p -- foo/bar        # (*)

creates foo as 'drwxr-xr-x' (note the missing g+w! foo), and what's worse,
$ mkdir -m u=rwx,g=rx,o=rx,u+wx -p -- foo/bar   # (**)

creates foo as 'd-wx-w--w-', and exits successfully.

$ tusc mkdir -m u=rwx,g=rx,o=rx,u+wx -p -- foo/bar
| execve("/bin/mkdir", 0x9ffffffffffffcc0, 0x9ffffffffffffcf8) = 0 [32-bit]
[...]
| fcntl(3, F_SETFD, 1) ..................................... = 0
| umask(0) ................................................. = 02
| umask(02) ................................................ = 0
| umask(0) ................................................. = 02
| umask(02) ................................................ = 0
| umask(0) ................................................. = 02
| umask(022) ............................................... = 0
| umask(0) ................................................. = 022
| umask(022) ............................................... = 0
| umask(0) ................................................. = 022
| umask(0777) .............................................. = 0
| umask(0) ................................................. = 0777
| umask(0777) .............................................. = 0
| mkdir("foo", 0777) ...................................... = 0
| chmod("foo", 0322) ...................................... = 0
| umask(0) ................................................. = 0777
| mkdir("foo/bar", 0755) ................................... = 0
| exit(0) .................................................. WIFEXITED(0)

What a pain!  The following doesn't work either:
$ mkdir -m 775,u+wx -p -- foo/bar

I will propose a patch in a followup post to the automake-patches list.
It would be good if someone with a HP contract could report this bug.

Weird though,
$ ( umask 077; mkdir -p -m 777 foo/bar )

works on HP-UX (in creating foo with mode 700), but on IRIX 6.5, which
shares the bug (*) but not (**) above, it creates foo with mode 777.

Cheers, and thanks again for your bug report,
Ralf




reply via email to

[Prev in Thread] Current Thread [Next in Thread]