Perl / perl5

🐪 The Perl programming language
https://dev.perl.org/perl5/
Other
1.9k stars 540 forks source link

Relocatable-perl on AIX does not run if added to PATH #11453

Open p5pRT opened 13 years ago

p5pRT commented 13 years ago

Migrated from rt.perl.org#93134 (status was 'open')

Searchable as RT93134$

p5pRT commented 13 years ago

From @dmcbride

Created by @dmcbride

If I compile perl 5.14.0 with -Duserelocatableinc\, and then relocate it afterward and add that to the PATH\, "perl -V" doesn't find Config.pm and thus dies.

$ perl -v

This is perl 5\, version 14\, subversion 0 (v5.14.0) built for aix-thread-multi-64all

Copyright 1987-2011\, Larry Wall

Perl may be copied only under the terms of either the Artistic License or the GNU General Public License\, which may be found in the Perl 5 source kit.

Complete documentation for Perl\, including FAQ lists\, should be found on this system using "man perl" or "perldoc perl". If you have access to the Internet\, point your browser at http​://www.perl.org/\, the Perl Home Page.

$ perl -V Can't locate Config.pm in @​INC (@​INC contains​: ../lib/site_perl/5.14.0/aix-thread-multi-64all ../lib/site_perl/5.14.0 ../lib/5.14.0/aix-thread-multi-64all ../lib/5.14.0 .).

When I try this on Linux\, it works. I suspect it has something to do with​:

$ perl -le 'print $^X' perl

whereas if I do the same thing on Linux\, I get a full path to perl in the relocated directory (not where it was compiled to install to). If I call the perl on AIX with a full or relative path\, it works fine.

Note that if I run perlbug\, whether on AIX or Linux\, it fails. The #! line combined with the eval 'exec ...' simply fail to find the perl it's associated with\, e.g.\, on Linux​:

$ perlbug bash​: /home/dmcbride/perl/tmp/foo/usr/opt/perl/bin/perlbug​: /usr/opt/perl/bin/perl​: bad interpreter​: No such file or directory

Perl Info ``` Flags: category=core severity=low Site configuration information for perl 5.14.0: Configured by dmcbride at Thu Jun 16 12:35:56 EDT 2011. Summary of my perl5 (revision 5 version 14 subversion 0) configuration: Platform: osname=aix, osvers=6.1.0.0, archname=aix-thread-multi-64all uname='aix hotelisasp01 1 6 00c1837d4c00 ' config_args='-d -Dcc=cc_r -Dusethreads -Duse64bitall -Dprefix=/opt/perl -Duserelocatableinc' hint=recommended, useposix=true, d_sigaction=define useithreads=define, usemultiplicity=define useperlio=define, d_sfio=undef, uselargefiles=define, usesocks=undef use64bitint=define, use64bitall=define, uselongdouble=undef usemymalloc=n, bincompat5005=undef Compiler: cc='cc_r -q64', ccflags ='-D_ALL_SOURCE -D_ANSI_C_SOURCE -D_POSIX_SOURCE -qmaxmem=-1 -qnoansialias -DUSE_NATIVE_DLOPEN -DNEED_PTHREAD_INIT -q64 -DUSE_64_BIT_ALL -q64', optimize='-O', cppflags='-D_ALL_SOURCE -D_ANSI_C_SOURCE -D_POSIX_SOURCE -qmaxmem=-1 -qnoansialias -DUSE_NATIVE_DLOPEN -DNEED_PTHREAD_INIT' ccversion='10.1.0.2', gccversion='', gccosandvers='' intsize=4, longsize=8, ptrsize=8, doublesize=8, byteorder=87654321 d_longlong=define, longlongsize=8, d_longdbl=define, longdblsize=8 ivtype='long long', ivsize=8, nvtype='double', nvsize=8, Off_t='off_t', lseeksize=8 alignbytes=8, prototype=define Linker and Libraries: ld='ld', ldflags ='-brtl -bdynamic -b64' libpth=/lib /usr/lib /usr/ccs/lib libs=-lbind -lnsl -ldbm -ldl -lld -lm -lcrypt -lpthreads -lc perllibs=-lbind -lnsl -ldl -lld -lm -lcrypt -lpthreads -lc libc=/lib/libc.a, so=a, useshrplib=false, libperl=libperl.a gnulibc_version='' Dynamic Linking: dlsrc=dl_aix.xs, dlext=so, d_dlsymun=undef, ccdlflags=' -bE:.../../lib/5.14.0/aix-thread-multi-64all/CORE/perl.exp' cccdlflags=' ', lddlflags='-b64 -bhalt:4 -G -bI:$(PERL_INC)/perl.exp -bE:$(BASEEXT).exp -bnoentry -lpthreads -lc -lm' Locally applied patches: @INC for perl 5.14.0: newperl/opt/perl/lib/site_perl/5.14.0/aix-thread-multi-64all newperl/opt/perl/lib/site_perl/5.14.0 newperl/opt/perl/lib/5.14.0/aix-thread-multi-64all newperl/opt/perl/lib/5.14.0 . Environment for perl 5.14.0: HOME=/home/dmcbride LANG=en_US LANGUAGE (unset) LC__FASTMSG=true LD_LIBRARY_PATH (unset) LIBPATH (unset) LOGDIR (unset) PATH=/usr/bin:/etc:/usr/sbin:/usr/ucb:/home/dmcbride/bin:/usr/bin/X11:/sbin:. PERL_BADLANG (unset) SHELL=/usr/bin/ksh ```
p5pRT commented 13 years ago

From @jandubois

On Mon\, 20 Jun 2011\, via RT wrote​:

If I compile perl 5.14.0 with -Duserelocatableinc\, and then relocate it afterward and add that to the PATH\, "perl -V" doesn't find Config.pm and thus dies.

[...]

When I try this on Linux\, it works. I suspect it has something to do with​:

$ perl -le 'print $^X' perl

whereas if I do the same thing on Linux\, I get a full path to perl in the relocated directory (not where it was compiled to install to). If I call the perl on AIX with a full or relative path\, it works fine.

That is indeed the problem​: -Duserelocatableinc really only works on Linux where $^X is set from /proc/self/exe. On other systems it just relies on the value of argv[0]\, which is typically not fully qualified.

I know how to make things work on OS X and Solaris as well\, but for AIX and HP-UX I don't know of any secure/reliable mechanism to determine the full path of the currently running executable.

On Windows this is not an issue as there @​INC is always determined at runtime relative to the location of the perl5xx.dll file.

Cheers\, -Jan

p5pRT commented 13 years ago

The RT System itself - Status changed from 'new' to 'open'

p5pRT commented 13 years ago

From darin.mcbride@shaw.ca

You mention that you don't know how on HPUX (which I don't care about right now)\, but searching for the AIX solution popped this up - the "pstat" answer looks most promising. I'm still searching for AIX.

http​://stackoverflow.com/questions/200737/get-full-path-of- executable-of-running-process-on-hpux

p5pRT commented 12 years ago

From @nwc10

On Mon\, Jun 20\, 2011 at 04​:59​:33PM -0700\, Jan Dubois wrote​:

On Mon\, 20 Jun 2011\, via RT wrote​:

If I compile perl 5.14.0 with -Duserelocatableinc\, and then relocate it afterward and add that to the PATH\, "perl -V" doesn't find Config.pm and thus dies.

[...]

When I try this on Linux\, it works. I suspect it has something to do with​:

$ perl -le 'print $^X' perl

whereas if I do the same thing on Linux\, I get a full path to perl in the relocated directory (not where it was compiled to install to). If I call the perl on AIX with a full or relative path\, it works fine.

That is indeed the problem​: -Duserelocatableinc really only works on Linux where $^X is set from /proc/self/exe. On other systems it just relies on the value of argv[0]\, which is typically not fully qualified.

I know how to make things work on OS X and Solaris as well\, but for AIX and HP-UX I don't know of any secure/reliable mechanism to determine the full path of the currently running executable.

With commit 6f31bef90fda3b9a I've merged code to make $^X absolute on OS X\, Solaris 10 and 11\, and FreeBSD without needing /proc mounted.

It would be possible to use getexecname() along with realpath() on earlier Solaris\, but I'm not sure if it's worth adding.

perl already uses /proc on Linux and NetBSD to convert $^X to an absolute path.

Like Jan\, I'm not aware of a reliable way to do this on any other platform. Likely it's not possible.

Nicholas Clark

p5pRT commented 12 years ago

From @icerider70

On Wed\, Sep 28\, 2011 at 5​:43 AM\, Nicholas Clark \nick@​ccl4\.org wrote​:

Like Jan\, I'm not aware of a reliable way to do this on any other platform. Likely it's not possible.

The following code snippet (found via stackoverflow)\, appears to work as advertised on HP-UX 11.23 and 11.31​:

#include \<stdio.h> #include \<stdlib.h> #include \<limits.h> #include \<unistd.h>

#define _PSTAT64 #include \<sys/pstat.h>

int main(int argc\, char *argv[]) {   char filename[PATH_MAX];   struct pst_status s;

  if (pstat_getproc(&s\,sizeof(s)\,0\,getpid()) == -1) {   perror("pstat_getproc");   return EXIT_FAILURE;   }

  if (pstat_getpathname(filename\,sizeof(filename)\,&s.pst_fid_text) == -1) {   perror("pstat_getpathname");   return EXIT_FAILURE;   }

  printf("filename​: %s\n"\,filename);

  return EXIT_SUCCESS; }

--Phil

p5pRT commented 12 years ago

From @nwc10

On Wed\, Sep 28\, 2011 at 12​:13​:49PM -0500\, Philip Monsen wrote​:

On Wed\, Sep 28\, 2011 at 5​:43 AM\, Nicholas Clark \nick@&#8203;ccl4\.org wrote​:

Like Jan\, I'm not aware of a reliable way to do this on any other platform. Likely it's not possible.

Good. Proven wrong on another platform. Are the rest "impossible" too? :-)

The following code snippet (found via stackoverflow)\, appears to work as advertised on HP-UX 11.23 and 11.31​:

#include \<stdio.h> #include \<stdlib.h> #include \<limits.h> #include \<unistd.h>

#define _PSTAT64 #include \<sys/pstat.h>

int main(int argc\, char *argv[]) { char filename[PATH_MAX]; struct pst_status s;

if (pstat_getproc(&s\,sizeof(s)\,0\,getpid()) == -1) { perror("pstat_getproc"); return EXIT_FAILURE; }

I don't have access to any HP-UX system\, so can't write code to test any of this. I think that the right approach would be a Configure probe\, perl.c change analogous to those for sysctl() and _NSGetExecutablePath()

http​://perl5.git.perl.org/perl.git/commit/2982a345b7a1edb6 http​://perl5.git.perl.org/perl.git/commit/ae60cb464cebf895

[the second patch was based on the first]

From searching online I find this piece of documentation​:

  On success\, the function returns the length of the   pathname copied starting at the location specified by   buf. If the pathname is not available in the system   cache\, 0 is returned and errno is not set. On other   failures\, the value of -1 is returned and errno is set   indicating the cause of the failure. This call does not   work for sockets.

if (pstat_getpathname(filename\,sizeof(filename)\,&s.pst_fid_text) == -1) { perror("pstat_getpathname"); return EXIT_FAILURE; }

printf("filename​: %s\n"\,filename);

return EXIT_SUCCESS; }

Which the sample code would fall foul of. I'm wondering what other gotchas are involved. The code you quote allowed me to find a link to this​: http​://h21007.www2.hp.com/portal/site/dspp/menuitem.863c3e4cbcdc3f3515b49c108973a801?ciid=88086d6e1de021106d6e1de02110275d6e10RCRD

which has this​:

Alternate program for 64-bit

#include \<dlfcn.h> #include \<unistd.h> #include \<stdlib.h> #include \<stdio.h> int main(int argc\, char *argv[]) {   struct load_module_desc desc;   char *name;   dlget(-2\, &desc\, sizeof(desc));   name = dlgetname(&desc\, sizeof(desc)\, NULL\, NULL\, NULL);   printf("executable is '%s' (from dlgetname).\n"\, name);   return 0; }

I have *no* idea of the relative merits of the two approaches when both are available. The latter looks less complex\, and less prone to failure\, but I've no idea what downsides it has.

Nicholas Clark  

p5pRT commented 12 years ago

From @icerider70

On Wed\, Sep 28\, 2011 at 1​:21 PM\, Nicholas Clark \nick@&#8203;ccl4\.org wrote​:

I have *no* idea of the relative merits of the two approaches when both are available. The latter looks less complex\, and less prone to failure\, but I've no idea what downsides it has.

Unfortunately\, the main downside is that it doesn't actually appear to provide a full path​:

# On both 11.23 and 11.31 $ ./my_dlget executable is './my_dlget' (from dlgetname).

I'm wondering if some guarantee is afforded for a process's executable name to be in the directory name lookup cache (DNLC) if its process information is queried immediately prior via pstat_getproc()\, as in the first code snippet. If there were\, then there'd be more assurance that pstat_getpathname() would return reliable information. The pstat docs don't say so (at least it doesn't jump right out)\, but since the DNLC is dumpable (per filesystem) via pstat_getmpathname()\, maybe it's possible to make some judgments based on empirical observation.

--Phil

p5pRT commented 12 years ago

From @icerider70

On Wed\, Sep 28\, 2011 at 2​:07 PM\, Philip Monsen \philip\.monsen@&#8203;gmail\.comwrote​:

I'm wondering if some guarantee is afforded for a process's executable name to be in the directory name lookup cache (DNLC) if its process information is queried immediately prior via pstat_getproc()\, as in the first code snippet. If there were\, then there'd be more assurance that pstat_getpathname() would return reliable information. The pstat docs don't say so (at least it doesn't jump right out)\, but since the DNLC is dumpable (per filesystem) via pstat_getmpathname()\, maybe it's possible to make some judgments based on empirical observation.

Doing this empirical test is pretty much a non-starter for me given the restriction to use of pstat_getmpathname() from the manpage\, and my local lack of the required credentials​:

  The use of this function is limited to UID 0.

--Phil

p5pRT commented 12 years ago

From tammer@tammer.net

Hello\, OK\, you are looking for something like this on AIX\, but in C without the use of system tools​:


#!/usr/bin/perl

@​proc = split/ /\,`procfiles $$|head -n 1`; if (-l $proc[2]) {   print `readlink $proc[2]`; } else {   print "$proc[2]\n"; }

exit 0;


# ./test.pl /usr/opt/perl5/bin/perl5.8.2

Bye   Rainer

p5pRT commented 8 years ago

From gskallur@gmail.com

This issue is there in perl 5.22.0 in AIX and HPIA. Please let me know if there is a work around

p5pRT commented 8 years ago

From [Unknown Contact. See original ticket]

This issue is there in perl 5.22.0 in AIX and HPIA. Please let me know if there is a work around

p5pRT commented 8 years ago

From gskallur@gmail.com

For HP-UX below approach is working. Can some one please validate.

Added the following code in perl_source/caretx.c

# elif defined(__hpux)   #include \<dlfcn.h>   struct load_module_desc desc;   char *name;   dlget(-2\, &desc\, sizeof(desc));   name = dlgetname(&desc\, sizeof(desc)\, NULL\, NULL\, NULL);   sv_setpv(caret_x\, name);   return;

p5pRT commented 8 years ago

From [Unknown Contact. See original ticket]

For HP-UX below approach is working. Can some one please validate.

Added the following code in perl_source/caretx.c

# elif defined(__hpux)   #include \<dlfcn.h>   struct load_module_desc desc;   char *name;   dlget(-2\, &desc\, sizeof(desc));   name = dlgetname(&desc\, sizeof(desc)\, NULL\, NULL\, NULL);   sv_setpv(caret_x\, name);   return;