This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
Fix original version of Socket in perldelta
[perl5.git] / caretx.c
CommitLineData
e2051532
PM
1/* caretx.c
2 *
3 * Copyright (C) 2013
4 * by Larry Wall and others
5 *
6 * You may distribute under the terms of either the GNU General Public
7 * License or the Artistic License, as specified in the README file.
8 *
9 */
10
11/*
7d087888
FC
12 * 'I do not know clearly,' said Frodo; 'but the path climbs, I think,
13 * up into the mountains on the northern side of that vale where the old
14 * city stands. It goes up to a high cleft and so down to -- that which
15 * is beyond.'
16 * 'Do you know the name of that high pass?' said Faramir.
17 *
97a07f93 18 * [p.691 of _The Lord of the Rings_, IV/xi: "The Forbidden Pool"]
e2051532
PM
19 */
20
21/* This file contains a single function, set_caret_X, to set the $^X
22 * variable. It's only used in perl.c, but has various OS dependencies,
23 * so its been moved to its own file to reduce header pollution.
24 * See RT 120314 for details.
25 */
26
27#if defined(PERL_IS_MINIPERL) && !defined(USE_SITECUSTOMIZE)
28# define USE_SITECUSTOMIZE
29#endif
30
31#include "EXTERN.h"
32#include "perl.h"
33#include "XSUB.h"
34
35#ifdef NETWARE
36#include "nwutil.h"
37#endif
38
39#ifdef USE_KERN_PROC_PATHNAME
40# include <sys/sysctl.h>
41#endif
42
43#ifdef USE_NSGETEXECUTABLEPATH
44# include <mach-o/dyld.h>
45#endif
46
c9a047cb
FC
47/* Note: Functions in this file must not have bool parameters. When
48 PERL_BOOL_AS_CHAR is #defined, mach-o/dyld.h overrides it in this file
49 by #including stdbool.h, so the function parameters here would conflict
50 with those in proto.h.
51*/
52
e2051532
PM
53void
54Perl_set_caret_X(pTHX) {
e2051532 55 GV* tmpgv = gv_fetchpvs("\030", GV_ADD|GV_NOTQUAL, SVt_PV); /* $^X */
eb4e1bae 56 SV *const caret_x = GvSV(tmpgv);
e2051532 57#if defined(OS2)
eb4e1bae 58 sv_setpv(caret_x, os2_execname(aTHX));
fca5fb96 59#elif defined(USE_KERN_PROC_PATHNAME)
eb4e1bae
DD
60 size_t size = 0;
61 int mib[4];
62 mib[0] = CTL_KERN;
63 mib[1] = KERN_PROC;
64 mib[2] = KERN_PROC_PATHNAME;
65 mib[3] = -1;
66
67 if (sysctl(mib, 4, NULL, &size, NULL, 0) == 0
68 && size > 0 && size < MAXPATHLEN * MAXPATHLEN) {
69 sv_grow(caret_x, size);
70
71 if (sysctl(mib, 4, SvPVX(caret_x), &size, NULL, 0) == 0
72 && size > 2) {
73 SvPOK_only(caret_x);
74 SvCUR_set(caret_x, size - 1);
75 SvTAINT(caret_x);
76 return;
e2051532 77 }
eb4e1bae 78 }
fca5fb96 79#elif defined(USE_NSGETEXECUTABLEPATH)
eb4e1bae
DD
80 char buf[1];
81 uint32_t size = sizeof(buf);
82
83 _NSGetExecutablePath(buf, &size);
84 if (size < MAXPATHLEN * MAXPATHLEN) {
85 sv_grow(caret_x, size);
86 if (_NSGetExecutablePath(SvPVX(caret_x), &size) == 0) {
87 char *const tidied = realpath(SvPVX(caret_x), NULL);
88 if (tidied) {
89 sv_setpv(caret_x, tidied);
90 free(tidied);
91 } else {
92 SvPOK_only(caret_x);
93 SvCUR_set(caret_x, size);
e2051532 94 }
eb4e1bae 95 return;
e2051532 96 }
eb4e1bae 97 }
fca5fb96 98#elif defined(HAS_PROCSELFEXE)
eb4e1bae
DD
99 char buf[MAXPATHLEN];
100 SSize_t len = readlink(PROCSELFEXE_PATH, buf, sizeof(buf) - 1);
101 /* NOTE: if the length returned by readlink() is sizeof(buf) - 1,
102 * it is impossible to know whether the result was truncated. */
51b468f6 103
eb4e1bae
DD
104 if (len != -1) {
105 buf[len] = '\0';
106 }
e2051532 107
eb4e1bae
DD
108 /* On Playstation2 Linux V1.0 (kernel 2.2.1) readlink(/proc/self/exe)
109 includes a spurious NUL which will cause $^X to fail in system
110 or backticks (this will prevent extensions from being built and
111 many tests from working). readlink is not meant to add a NUL.
112 Normal readlink works fine.
113 */
114 if (len > 0 && buf[len-1] == '\0') {
115 len--;
116 }
e2051532 117
eb4e1bae
DD
118 /* FreeBSD's implementation is acknowledged to be imperfect, sometimes
119 returning the text "unknown" from the readlink rather than the path
120 to the executable (or returning an error from the readlink). Any
121 valid path has a '/' in it somewhere, so use that to validate the
122 result. See http://www.freebsd.org/cgi/query-pr.cgi?pr=35703
123 */
124 if (len > 0 && memchr(buf, '/', len)) {
125 sv_setpvn(caret_x, buf, len);
126 return;
127 }
fca5fb96 128#elif defined(WIN32)
7175d769
DD
129 char *ansi;
130 WCHAR widename[MAX_PATH];
131 GetModuleFileNameW(NULL, widename, sizeof(widename)/sizeof(WCHAR));
132 ansi = win32_ansipath(widename);
133 sv_setpv(caret_x, ansi);
134 win32_free(ansi);
135 return;
fca5fb96 136#else
eb4e1bae
DD
137 /* Fallback to this: */
138 sv_setpv(caret_x, PL_origargv[0]);
e2051532 139#endif
e2051532
PM
140}
141
142/*
e2051532
PM
143 * ex: set ts=8 sts=4 sw=4 et:
144 */