summaryrefslogtreecommitdiff
path: root/tests/misc/pwd-long
blob: 7fa95abc0f411f158bb339fe64c61b877ca81331 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
#!/bin/sh
# -*- perl -*-
# Ensure that pwd works even when run from a very deep directory.

# Copyright (C) 2006-2011 Free Software Foundation, Inc.

# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.

# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.

# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.

: ${srcdir=.}
. $srcdir/require-perl

. "${srcdir=.}/init.sh"; path_prepend_ ../src
print_ver_ pwd

require_readable_root_

ARGV_0=$0
export ARGV_0

# Don't use CuTmpdir here, since File::Temp's use of rmtree can't
# remove the deep tree we create.
$PERL -Tw -- - <<\EOF

# Show that pwd works even when the length of the resulting
# directory name is longer than PATH_MAX.
use strict;

(my $ME = $ENV{ARGV_0}) =~ s|.*/||;

sub normalize_to_cwd_relative ($$$)
{
  my ($dir, $dev, $ino) = @_;
  my $slash = -1;
  my $next_slash;
  while (1)
    {
      $slash = index $dir, '/', $slash + 1;
      $slash <= -1
        and die "$ME: $dir does not contain old CWD\n";
      my $dir_prefix = $slash ? substr ($dir, 0, $slash) : '/';
      my ($d, $i) = (stat $dir_prefix)[0, 1];
      $d eq $dev && $i eq $ino
        and return substr $dir, $slash + 1;
    }
}

# Set up a safe, well-known environment
delete @ENV{qw(BASH_ENV CDPATH ENV)};
$ENV{IFS}  = '';

# Taint checking requires a sanitized $PATH.  This script performs no $PATH
# search, so on most Unix-based systems, it is fine simply to clear $ENV{PATH}.
# However, on Cygwin, it's used to find cygwin1.dll, so set it.
$ENV{PATH} = '/bin:/usr/bin';

# Save CWD's device and inode numbers.
my ($dev, $ino) = (stat '.')[0, 1];

# Construct the expected "."-relative part of pwd's output.
my $z = 'z' x 31;
my $n = 256;
my $expected = "/$z" x $n;
# Remove the leading "/".
substr ($expected, 0, 1) = '';

my $i = 0;
do
  {
    if (!mkdir $z, 0700)
      {
        warn "$ME: skipping this test; cannot create long directory name "
          . "at depth $i: $!\n";
        exit 77;
      }
    chdir $z
  }
until (++$i == $n);

my $abs_top_builddir = $ENV{abs_top_builddir};
$abs_top_builddir
  or die "$ME: envvar abs_top_builddir not defined\n";
my $build_src_dir = "$abs_top_builddir/src";
if ($build_src_dir !~ m!^([-+.:/\w]+)$!)
  {
    warn "$ME: skipping this test; odd build source directory name:\n"
      . "$build_src_dir\n";
    exit 77;
  }
$build_src_dir = $1;

my $pwd_binary = "$build_src_dir/pwd";

-x $pwd_binary
  or die "$ME: $pwd_binary is not an executable file\n";
chomp (my $actual = `$pwd_binary`);

# Convert the absolute name from pwd into a $CWD-relative name.
# This is necessary in order to avoid a spurious failure when run
# from a directory in a bind-mounted partition.  What happens is
# pwd reads a ".." that contains two or more entries with identical
# dev,ino that match the ones we're looking for, and it chooses a
# name that does not correspond to the one already recorded in $CWD.
$actual = normalize_to_cwd_relative $actual, $dev, $ino;

if ($expected ne $actual)
  {
    my $e_len = length $expected;
    my $a_len = length $actual;
    warn "expected len: $e_len\n";
    warn "actual len:   $a_len\n";
    warn "expected: $expected\n";
    warn "actual: $actual\n";
    exit 1;
  }
EOF

fail=$?

Exit $fail