Well I've hacked this, but I'm not very proud of it and I hope someone comes up with something better. I've searched the CPAN but am surprised to have found nothing relevant
My idea was to use the abs2rel function from File::Spec::Functions. That's fine, except that it tries too hard for this purpose and will return ../.. for abs2rel('/usr', '/usr/a/b'). It will also return the first value unchanged on systems that use volumes in the path
This just wraps abs2rel inside a function is_within which rejects both of those cases, but otherwise returns the relative path (a true value) intact. That means that is within('/usr', '/usr') will return ., which is true, but you can test it for that specific case if you think a directory shouldn't contain itself
Note that this doesn't check whether the paths are to directories, nor does it check whether the paths even exist
use strict;
use warnings 'all';
use File::Spec::Functions qw/ abs2rel  file_name_is_absolute  updir /;
my @pairs = (
    [qw{ /usr      /usr/bin } ],
    [qw{ /usr/etc  /usr/bin } ],
    [qw{ /var      /usr/bin } ],
    [qw{ /usr/bin  /usr/bin } ],
);
for ( @pairs ) {
    my ($path, $subpath) = @$_;
    my $within = is_within($subpath, $path);
    printf qq{"%s" is %swithin "%s"  (%s)\n},
            $subpath,
            ($within ? '' : 'not '),
            $path,
            $within // 'undef';
}
sub is_within {
    my ($path, $container) = @_;
    my $a2r = abs2rel($path, $container);
    return if file_name_is_absolute($a2r) or index($a2r, updir) == 0;
    $a2r;
}
output
"/usr/bin" is within "/usr"  (bin)
"/usr/bin" is not within "/usr/etc"  (undef)
"/usr/bin" is not within "/var"  (undef)
"/usr/bin" is within "/usr/bin"  (.)