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
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
|
#!./perl
#
# Tests for perl exit codes, playing with $?, etc...
BEGIN {
chdir 't' if -d 't';
@INC = qw(. ../lib);
}
# Run some code, return its wait status.
sub run {
my($code) = shift;
$code = "\"" . $code . "\"" if $^O eq 'VMS'; #VMS needs quotes for this.
return system($^X, "-e", $code);
}
BEGIN {
$numtests = ($^O eq 'VMS') ? 16 : 17;
}
my $vms_exit_mode = 0;
if ($^O eq 'VMS') {
if (eval 'require VMS::Feature') {
$vms_exit_mode = !(VMS::Feature::current("posix_exit"));
} else {
my $env_unix_rpt = $ENV{'DECC$FILENAME_UNIX_REPORT'} || '';
my $env_posix_ex = $ENV{'PERL_VMS_POSIX_EXIT'} || '';
my $unix_rpt = $env_unix_rpt =~ /^[ET1]/i;
my $posix_ex = $env_posix_ex =~ /^[ET1]/i;
if (($unix_rpt || $posix_ex) ) {
$vms_exit_mode = 0;
} else {
$vms_exit_mode = 1;
}
}
$numtests = 29 unless $vms_exit_mode;
}
require "test.pl";
plan(tests => $numtests);
my $native_success = 0;
$native_success = 1 if $^O eq 'VMS';
my $exit, $exit_arg;
$exit = run('exit');
is( $exit >> 8, 0, 'Normal exit' );
is( $exit, $?, 'Normal exit $?' );
is( ${^CHILD_ERROR_NATIVE}, $native_success, 'Normal exit ${^CHILD_ERROR_NATIVE}' );
if (!$vms_exit_mode) {
my $posix_ok = eval { require POSIX; };
my $wait_macros_ok = defined &POSIX::WIFEXITED;
eval { POSIX::WIFEXITED(${^CHILD_ERROR_NATIVE}) };
$wait_macros_ok = 0 if $@;
$exit = run('exit 42');
is( $exit >> 8, 42, 'Non-zero exit' );
is( $exit, $?, 'Non-zero exit $?' );
isnt( !${^CHILD_ERROR_NATIVE}, 0, 'Non-zero exit ${^CHILD_ERROR_NATIVE}' );
SKIP: {
skip("No POSIX", 3) unless $posix_ok;
skip("No POSIX wait macros", 3) unless $wait_macros_ok;
ok(POSIX::WIFEXITED(${^CHILD_ERROR_NATIVE}), "WIFEXITED");
ok(!POSIX::WIFSIGNALED(${^CHILD_ERROR_NATIVE}), "WIFSIGNALED");
is(POSIX::WEXITSTATUS(${^CHILD_ERROR_NATIVE}), 42, "WEXITSTATUS");
}
SKIP: {
skip("Skip signals and core dump tests on Win32 and VMS", 7)
if ($^O eq 'MSWin32' || $^O eq 'VMS');
#TODO VMS will backtrace on this test and exits with code of 0
#instead of 15.
$exit = run('kill 15, $$; sleep(1);');
is( $exit & 127, 15, 'Term by signal' );
ok( !($exit & 128), 'No core dump' );
is( $? & 127, 15, 'Term by signal $?' );
isnt( ${^CHILD_ERROR_NATIVE}, 0, 'Term by signal ${^CHILD_ERROR_NATIVE}' );
SKIP: {
skip("No POSIX", 3) unless $posix_ok;
skip("No POSIX wait macros", 3) unless $wait_macros_ok;
ok(!POSIX::WIFEXITED(${^CHILD_ERROR_NATIVE}), "WIFEXITED");
ok(POSIX::WIFSIGNALED(${^CHILD_ERROR_NATIVE}), "WIFSIGNALED");
is(POSIX::WTERMSIG(${^CHILD_ERROR_NATIVE}), 15, "WTERMSIG");
}
}
}
if ($^O eq 'VMS') {
# On VMS, successful returns from system() are reported 0, VMS errors that
# can not be translated to UNIX are reported as EVMSERR, which has a value
# of 65535. Codes from 2 through 7 are assumed to be from non-compliant
# VMS systems and passed through. Programs written to use _POSIX_EXIT()
# codes like GNV will pass the numbers 2 through 255 encoded in the
# C facility by multiplying the number by 8 and adding %x35A000 to it.
# Perl will decode that number from children back to it's internal status.
#
# For native VMS status codes, success codes are odd numbered, error codes
# are even numbered. The 3 LSBs of the code indicate if the success is
# an informational message or the severity of the failure.
#
# Because the failure codes for the tests of the CLI facility status codes can
# not be translated to UNIX error codes, they will be reported as EVMSERR,
# even though Perl will exit with them having the VMS status codes.
#
# Note that this is testing the perl exit() routine, and not the VMS
# DCL EXIT statement.
#
# The value %x1000000 has been added to the exit code to prevent the
# status message from being sent to the STDOUT and STDERR stream.
#
# Double quotes are needed to pass these commands through DCL to PERL
$exit = run("exit 268632065"); # %CLI-S-NORMAL
is( $exit >> 8, 0, 'PERL success exit' );
is( ${^CHILD_ERROR_NATIVE} & 7, 1, 'VMS success exit' );
$exit = run("exit 268632067"); # %CLI-I-NORMAL
is( $exit >> 8, 0, 'PERL informational exit' );
is( ${^CHILD_ERROR_NATIVE} & 7, 3, 'VMS informational exit' );
$exit = run("exit 268632064"); # %CLI-W-NORMAL
is( $exit >> 8, 1, 'Perl warning exit' );
is( ${^CHILD_ERROR_NATIVE} & 7, 0, 'VMS warning exit' );
$exit = run("exit 268632066"); # %CLI-E-NORMAL
is( $exit >> 8, 2, 'Perl error exit' );
is( ${^CHILD_ERROR_NATIVE} & 7, 2, 'VMS error exit' );
$exit = run("exit 268632068"); # %CLI-F-NORMAL
is( $exit >> 8, 4, 'Perl fatal error exit' );
is( ${^CHILD_ERROR_NATIVE} & 7, 4, 'VMS fatal exit' );
$exit = run("exit 02015320012"); # POSIX exit code 1
is( $exit >> 8, 1, 'Posix exit code 1' );
$exit = run("exit 02015323771"); # POSIX exit code 255
is( $exit >> 8 , 255, 'Posix exit code 255' );
}
$exit_arg = 42;
$exit = run("END { \$? = $exit_arg }");
# On VMS, in the child process the actual exit status will be SS$_ABORT,
# or 44, which is what you get from any non-zero value of $? except for
# 65535 that has been dePOSIXified by STATUS_UNIX_SET. If $? is set to
# 65535 internally when there is a VMS status code that is valid, and
# when Perl exits, it will set that status code.
#
# In this test on VMS, the child process exit with a SS$_ABORT, which
# the parent stores in ${^CHILD_ERROR_NATIVE}. The SS$_ABORT code is
# then translated to the UNIX code EINTR which has the value of 4 on VMS.
#
# This is complex because Perl translates internally generated UNIX
# status codes to SS$_ABORT on exit, but passes through unmodified UNIX
# status codes that exit() is called with by scripts.
$exit_arg = (44 & 7) if $vms_exit_mode;
is( $exit >> 8, $exit_arg, 'Changing $? in END block' );
|