=head1 NAME
-perlos2 - Perl under OS/2, Win0.31, Win0.95 and WinNT.
+perlos2 - Perl under OS/2, DOS, Win0.3*, Win0.95 and WinNT.
=head1 SYNOPSIS
to list some (not all may be available simultaneously), or it may
be read I<as is>: either as F<README.os2>, or F<pod/perlos2.pod>.
+To read the F<.INF> version of documentation (B<very> recommended)
+outside of OS/2, one needs an IBM's reader (may be available on IBM
+ftp sites (?) (URL anyone?)) or shipped with PC DOS 7.0.
+
=cut
Contents
- Starting Perl programs under OS/2
- Starting OS/2 programs under Perl
Frequently asked questions
- - I cannot run extenal programs
+ - I cannot run external programs
- I cannot embed perl into my program, or use perl.dll from my program.
INSTALLATION
- Automatic binary installation
- TMP or TEMP
Evolution
- Priorities
- - DLL name mungling
+ - DLL name mangling
- Threading
- Calls to external programs
AUTHOR
=head2 Target
The target is to make OS/2 the best supported platform for
-using/building/developping Perl and I<Perl applications>, as well as
+using/building/developing Perl and I<Perl applications>, as well as
make Perl the best language to use under OS/2.
The current state is quite close to this target. Known limitations:
There is no simple way to access B<WPS> objects. The only way I know
is via C<OS2::REXX> extension (see L<OS2::REXX>), and we do not have access to
-convinience methods of B<Object REXX>. (Is it possible at all? I know
+convenience methods of B<Object REXX>. (Is it possible at all? I know
of no B<Object-REXX> API.)
=back
Since OS/2 port of perl uses a remarkable B<EMX> environment, it can
run (and build extensions, and - possibly - be build itself) under any
environment which can run EMX. The current list is DOS,
-DOS-inside-OS/2, Win0.31, Win0.95 and WinNT. Out of many perl flavors,
+DOS-inside-OS/2, Win0.3*, Win0.95 and WinNT. Out of many perl flavors,
only one works, see L<"perl_.exe">.
Note that not all features of Perl are available under these
B<EMX> runtime is required (may be substituted by B<RSX>). Note that
it is possible to make F<perl_.exe> to run under DOS without any
-external support by binding F<emx.exe> to it, see L<emxbind>. Note
+external support by binding F<emx.exe>/F<rsx.exe> to it, see L<emxbind>. Note
that under DOS for best results one should use B<RSX> runtime, which
has much more functions working (like C<fork>, C<popen> and so on). In
-fact B<RSX> is required if there is no C<VCPI> present.
+fact B<RSX> is required if there is no C<VCPI> present. Note the
+B<RSX> requires C<DPMI>.
Only the latest runtime is supported, currently C<0.9c>.
The runtime component should have the name F<emxrt.zip>.
+B<NOTE>. It is enough to have F<emx.exe>/F<rsx.exe> on your path. One
+does not need to specify them explicitly (though this
+
+ emx perl_.exe -de 0
+
+will work as well.)
+
=item B<RSX>
-To run Perl on C<DPMS> platforms one needs B<RSX> runtime. This is
-needed under DOS-inside-OS/2, Win0.31, Win0.95 and WinNT (see
-L<"Other OSes">). I do not know whether B<RSX> would work with C<VCPI>
-only, as B<EMX> would.
+To run Perl on C<DPMI> platforms one needs B<RSX> runtime. This is
+needed under DOS-inside-OS/2, Win0.3*, Win0.95 and WinNT (see
+L<"Other OSes">). B<RSX> would not work with C<VCPI>
+only, as B<EMX> would, it requires C<DMPI>.
Having B<RSX> and the latest F<sh.exe> one gets a fully functional
B<*nix>-ish environment under DOS, say, C<fork>, C<``> and
or whatever method you prefer.
-There are also endless possibilites to use I<executable extensions> of
+There are also endless possibilities to use I<executable extensions> of
B<4OS2>, I<associations> of B<WPS> and so on... However, if you use
*nixish shell (like F<sh.exe> supplied in the binary distribution),
-you need follow the syntax specified in L<perlrun/"Switches">.
+you need to follow the syntax specified in L<perlrun/"Switches">.
=head2 Starting OS/2 programs under Perl
=head1 Frequently asked questions
-=head2 I cannot run extenal programs
+=head2 I cannot run external programs
=over 4
Do you try to run I<internal> shell commands, like C<`copy a b`>
(internal for F<cmd.exe>), or C<`glob a*b`> (internal for ksh)? You
-need to specify your shell explicitely, like C<`cmd /c copy a b`>,
+need to specify your shell explicitly, like C<`cmd /c copy a b`>,
since Perl cannot deduce which commands are internal to your shell.
=back
=head2 C<``> and pipe-C<open> do not work under DOS.
-This may a variant of just L<"I cannot run extenal programs">, or a
+This may a variant of just L<"I cannot run external programs">, or a
deeper problem. Basically: you I<need> B<RSX> (see L<"Prerequisites">)
-for these commands to work, and you need a port of F<sh.exe> which
+for these commands to work, and you may need a port of F<sh.exe> which
understands command arguments. One of such ports is listed in
L<"Prerequisites"> under B<RSX>.
-I do not know whether C<DPMI> is required.
+C<DPMI> is required for B<RSX>.
=head1 INSTALLATION
=head2 Automatic binary installation
-The most convinient way of installing perl is via perl installer
+The most convenient way of installing perl is via perl installer
F<install.exe>. Just follow the instructions, and 99% of the
installation blues would go away.
=head2 Manual binary installation
-As of version 5.00305, OS/2 perl binary distribution comes splitted
+As of version 5.00305, OS/2 perl binary distribution comes split
into 11 components. Unfortunately, to enable configurable binary
installation, the file paths in the C<zip> files are not absolute, but
relative to some directory.
(default with C<unzip>, specify C<-d> to C<pkunzip>). However, you
need to know where to extract the files. You need also to manually
change entries in F<Config.sys> to reflect where did you put the
-files.
+files. Note that if you have some primitive unzipper (like
+C<pkunzip>), you may get a lot of warnings/errors during
+unzipping. Upgrade to C<(w)unzip>.
Below is the sample of what to do to reproduce the configuration on my
machine:
unzip perl_sh.zip -d f:/bin
-This is used by perl to run external commands which explicitely
+This is used by perl to run external commands which explicitly
require shell, like the commands using I<redirection> and I<shell
metacharacters>. It is also used instead of explicit F</bin/sh>.
=head2 OS/2 F<.INF> file
-Most probably the most convinient form. View it as
+Most probably the most convenient form. View it as
view perl
view perl perlfunc
perldoc less
perldoc ExtUtils::MakeMaker
-to access the perl documention in the text form (note that you may get
+to access the perl documentation in the text form (note that you may get
better results using perl manpages).
Alternately, try running pod2text on F<.pod> files.
explore file:///f:/perllib/lib/pod/perl.html
-Alternatively you may be able to get these docs prebuild from C<CPAN>.
+Alternatively you may be able to get these docs prebuilt from C<CPAN>.
=head2 B<GNU> C<info> files
link386
shows you do not have it, do I<Selective install>, and choose C<Link
-object modules> in I<Optional system utilites/More>. If you get into
+object modules> in I<Optional system utilities/More>. If you get into
C<link386>, press C<Ctrl-C>.
=head2 Getting perl source
-You need to fetch the latest perl source (including developpers
+You need to fetch the latest perl source (including developers
releases). With some probability it is located in
http://www.perl.com/CPAN/src/5.0
If not, you may need to dig in the indices to find it in the directory
of the current maintainer.
-Quick cycle of developpers release may break the OS/2 build time to
+Quick cycle of developers release may break the OS/2 build time to
time, looking into
http://www.perl.com/CPAN/ports/os2/ilyaz/
make test
-Some tests (5..7) should fail. Some perl invocations should end in a
+Some tests (4..6) should fail. Some perl invocations should end in a
segfault (system error C<SYS3175>). To get finer error reports,
cd t
lib/io_pipe.t 3 768 6 ?? % ??
lib/io_sock.t 3 768 5 ?? % ??
op/stat.t 56 5 8.93% 3-4, 20, 35, 39
- Failed 4/118 test scripts, 96.61% okay. 27/2445 subtests failed, 98.90% okay.
+ Failed 4/140 test scripts, 97.14% okay. 27/2937 subtests failed, 99.08% okay.
Note that using `make test' target two more tests may fail: C<op/exec:1>
because of (mis)feature of C<pdksh>, and C<lib/posix:15>, which checks
that the buffers are not flushed on C<_exit> (this is a bug in the test
which assumes that tty output is buffered).
+I submitted a patch to B<EMX> which makes it possible to fork() with EMX
+dynamic libraries loaded, which makes F<lib/io*> tests pass. This means
+that soon the number of failing tests may decrease yet more.
+
+However, the test F<lib/io_udp.t> is disabled, since it never ends, I
+do not know why.
+
The reasons for failed tests are:
=over 8
Manually put F<perl_.exe> to a location on your C<PATH>.
Since C<perl_> has the extensions prebuilt, it does not suffer from
-the I<dynamic extensions + fork()> syndrom, thus the failing tests
+the I<dynamic extensions + fork()> syndrome, thus the failing tests
look like
Failed Test Status Wstat Total Fail Failed List of failed
Note that these functions are compatible with *nix, not with the older
ports of '94 - 95. The priorities are absolute, go from 32 to -95,
-lower is quickier. 0 is the default priority.
+lower is quicker. 0 is the default priority.
=head2 C<system()>
to DLLs having functions with REXX signature and to REXX runtime, to
OS/2 databases in the F<.INI> format, and to Extended Attributes.
-Two additional extensions by Andread Kaiser, C<OS2::UPM>, and
+Two additional extensions by Andreas Kaiser, C<OS2::UPM>, and
C<OS2::FTP>, are included into my ftp directory, mirrored on CPAN.
=head2 Prebuilt methods:
=item C<DynaLoader::mod2fname>
-used by C<DynaLoader> for DLL name mungling.
+used by C<DynaLoader> for DLL name mangling.
=item C<Cwd::current_drive()>
=item
-Since F<sh.exe> is used for globbing (see L<perlfunc/glob>), the bugs
+Since F<sh.exe> is used for globing (see L<perlfunc/glob>), the bugs
of F<sh.exe> plague perl as well.
In particular, uppercase letters do not work in C<[...]>-patterns with
=item C<popen>
-C<my_popen> always uses F<sh.exe>, cf. L<"PERL_SH_DIR">.
+C<my_popen> uses F<sh.exe> if shell is required, cf. L<"PERL_SH_DIR">.
=item C<tmpnam>
=item C<tmpfile>
-If the current directory is not writable, it is created using modified
+If the current directory is not writable, file is created using modified
C<tmpnam>, so there may be a race condition.
=item C<ctermid>
=head1 Perl flavors
-Because of ideosyncrasies of OS/2 one cannot have all the eggs in the
+Because of idiosyncrasies of OS/2 one cannot have all the eggs in the
same basket (though C<EMX> environment tries hard to overcome this
limitations, so the situation may somehow improve). There are 4
executables for Perl provided by the distribution:
C<VIO> application.
It can load perl dynamic extensions, and it can fork(). Unfortunately,
-currently it cannot fork() with dynamic extensions loaded.
+with the current version of B<EMX> it cannot fork() with dynamic
+extensions loaded (may be fixed by patches to B<EMX>).
B<Note.> Keep in mind that fork() is needed to open a pipe to yourself.
I<This is also the only executable with does not require OS/2.> The
friends locked into C<M$> world would appreciate the fact that this
-executable runs under DOS, Win0.31, Win0.95 and WinNT with an
+executable runs under DOS, Win0.3*, Win0.95 and WinNT with an
appropriate extender. See L<"Other OSes">.
=head2 F<perl__.exe>
L<perldiag/"No Perl script found in input">), it should know when a
program I<is a Perl>. There is some naming convention which allows
Perl to distinguish correct lines from wrong ones. The above names are
-almost the only names allowed by this convension which do not contain
+almost the only names allowed by this convention which do not contain
digits (which have absolutely different semantics).
=head2 Why dynamic linking?
additional work to make it compile. The reason is stupid-but-quick
"hard" dynamic linking used by OS/2.
-The address tables of DLLs are patches only once, when they are
-loaded. The addresses of entry points into DLLs are guarantied to be
+The address tables of DLLs are patched only once, when they are
+loaded. The addresses of entry points into DLLs are guaranteed to be
the same for all programs which use the same DLL, which reduces the
amount of runtime patching - once DLL is loaded, its code is
read-only.
While this allows some performance advantages, this makes life
-terrible for developpers, since the above scheme makes it impossible
+terrible for developers, since the above scheme makes it impossible
for a DLL to be resolved to a symbol in the .EXE file, since this
would need a DLL to have different relocations tables for the
executables which use it.
interpreter should be contained in a DLL, and the F<.EXE> file just loads
this DLL into memory and supplies command-arguments.
-This I<greately> increases the load time for the application (as well as
+This I<greatly> increases the load time for the application (as well as
the number of problems during compilation). Since interpreter is in a DLL,
the C<CRT> is basically forced to reside in a DLL as well (otherwise
extensions would not be able to use C<CRT>).
C<setpriority> and C<getpriority> are not compatible with earlier
ports by Andreas Kaiser. See C<"setpriority, getpriority">.
-=head2 DLL name mungling
+=head2 DLL name mangling
With the release 5.003_01 the dynamically loadable libraries
should be rebuilt. In particular, DLLs are now created with the names
=head2 Calls to external programs
Due to a popular demand the perl external program calling has been
-changed wrt Andread Kaiser's port. I<If> perl needs to call an
+changed wrt Andreas Kaiser's port. I<If> perl needs to call an
external program I<via shell>, the F<f:/bin/sh.exe> will be called, or
whatever is the override, see L<"PERL_SH_DIR">.
B<Disadvantages:> currently F<sh.exe> of C<pdksh> calls external programs
via fork()/exec(), and there is I<no> functioning exec() on
OS/2. exec() is emulated by EMX by asyncroneous call while the caller
-waits for child completion (to pretend that the pid did not change). This
+waits for child completion (to pretend that the C<pid> did not change). This
means that 1 I<extra> copy of F<sh.exe> is made active via fork()/exec(),
which may lead to some resources taken from the system (even if we do
not count extra work needed for fork()ing).
-One can always start F<cmd.exe> explicitely via
+Note that this a lesser issue now when we do not spawn F<sh.exe>
+unless needed (metachars found).
+
+One can always start F<cmd.exe> explicitly via
system 'cmd', '/c', 'mycmd', 'arg1', 'arg2', ...
-If you need to use F<cmd.exe>, and do not want to hand-edit thousends of your
+If you need to use F<cmd.exe>, and do not want to hand-edit thousands of your
scripts, the long-term solution proposed on p5-p is to have a directive
use OS2::Cmd;
OS/2 extensions
~~~~~~~~~~~~~~~
-I include 3 extensions by Andread Kaiser, OS2::REXX, OS2::UPM, and OS2::FTP,
+I include 3 extensions by Andreas Kaiser, OS2::REXX, OS2::UPM, and OS2::FTP,
into my ftp directory, mirrored on CPAN. I made
some minor changes needed to compile them by standard tools. I cannot
test UPM and FTP, so I will appreciate your feedback. Other extensions
#include <errno.h>
#include <limits.h>
#include <process.h>
+#include <fcntl.h>
#include "EXTERN.h"
#include "perl.h"
/*****************************************************************************/
+/* 2.1 would not resolve symbols on demand, and has no ExtLIBPATH. */
+static PFN ExtFCN[2]; /* Labeled by ord below. */
+static USHORT loadOrd[2] = { 874, 873 }; /* Query=874, Set=873. */
+#define ORD_QUERY_ELP 0
+#define ORD_SET_ELP 1
+
+APIRET
+loadByOrd(ULONG ord)
+{
+ if (ExtFCN[ord] == NULL) {
+ static HMODULE hdosc = 0;
+ BYTE buf[20];
+ PFN fcn;
+ APIRET rc;
+
+ if ((!hdosc && CheckOSError(DosLoadModule(buf, sizeof buf,
+ "doscalls", &hdosc)))
+ || CheckOSError(DosQueryProcAddr(hdosc, loadOrd[ord], NULL, &fcn)))
+ die("This version of OS/2 does not support doscalls.%i",
+ loadOrd[ord]);
+ ExtFCN[ord] = fcn;
+ }
+ if ((long)ExtFCN[ord] == -1) die("panic queryaddr");
+}
+
/* priorities */
static signed char priors[] = {0, 1, 3, 2}; /* Last two interchanged,
self inverse. */
/*****************************************************************************/
/* spawn */
+typedef void (*Sigfunc) _((int));
+
+static
+Sigfunc rsignal(signo,handler)
+int signo;
+Sigfunc handler;
+{
+ struct sigaction act,oact;
+
+ act.sa_handler = handler;
+ sigemptyset(&act.sa_mask);
+ act.sa_flags = 0;
+ if (sigaction(signo, &act, &oact) < 0)
+ return(SIG_ERR);
+ else
+ return(oact.sa_handler);
+}
static int
result(int flag, int pid)
return pid;
#ifdef __EMX__
- ihand = signal(SIGINT, SIG_IGN);
- qhand = signal(SIGQUIT, SIG_IGN);
+ ihand = rsignal(SIGINT, SIG_IGN);
+ qhand = rsignal(SIGQUIT, SIG_IGN);
do {
r = wait4pid(pid, &status, 0);
} while (r == -1 && errno == EINTR);
- signal(SIGINT, ihand);
- signal(SIGQUIT, qhand);
+ rsignal(SIGINT, ihand);
+ rsignal(SIGQUIT, qhand);
statusvalue = (U16)status;
if (r < 0)
return -1;
return status & 0xFFFF;
#else
- ihand = signal(SIGINT, SIG_IGN);
+ ihand = rsignal(SIGINT, SIG_IGN);
r = DosWaitChild(DCWA_PROCESS, DCWW_WAIT, &res, &rpid, pid);
- signal(SIGINT, ihand);
+ rsignal(SIGINT, ihand);
statusvalue = res.codeResult << 8 | res.codeTerminate;
if (r)
return -1;
#define EXECF_SPAWN 0
#define EXECF_EXEC 1
#define EXECF_TRUEEXEC 2
+#define EXECF_SPAWN_NOWAIT 3
int
do_spawn2(cmd, execf)
return execl(shell,shell,copt,cmd,(char*)0);
else if (execf == EXECF_EXEC)
return spawnl(P_OVERLAY,shell,shell,copt,cmd,(char*)0);
+ else if (execf == EXECF_SPAWN_NOWAIT)
+ return spawnl(P_NOWAIT,shell,shell,copt,cmd,(char*)0);
/* In the ak code internal P_NOWAIT is P_WAIT ??? */
rc = result(P_WAIT,
spawnl(P_NOWAIT,shell,shell,copt,cmd,(char*)0));
rc = execvp(Argv[0],Argv);
else if (execf == EXECF_EXEC)
rc = spawnvp(P_OVERLAY,Argv[0],Argv);
+ else if (execf == EXECF_SPAWN_NOWAIT)
+ rc = spawnvp(P_NOWAIT,Argv[0],Argv);
else
rc = result(P_WAIT, spawnvp(P_NOWAIT,Argv[0],Argv));
if (rc < 0 && dowarn)
return do_spawn2(cmd, EXECF_SPAWN);
}
+int
+do_spawn_nowait(cmd)
+char *cmd;
+{
+ return do_spawn2(cmd, EXECF_SPAWN_NOWAIT);
+}
+
bool
do_exec(cmd)
char *cmd;
char *cmd;
char *mode;
{
+#ifndef USE_POPEN
+
+ int p[2];
+ register I32 this, that, newfd;
+ register I32 pid, rc;
PerlIO *res;
SV *sv;
+
+ if (pipe(p) < 0)
+ return Nullfp;
+ /* `this' is what we use in the parent, `that' in the child. */
+ this = (*mode == 'w');
+ that = !this;
+ if (tainting) {
+ taint_env();
+ taint_proper("Insecure %s%s", "EXEC");
+ }
+ /* Now we need to spawn the child. */
+ newfd = dup(*mode == 'r'); /* Preserve std* */
+ if (p[that] != (*mode == 'r')) {
+ dup2(p[that], *mode == 'r');
+ close(p[that]);
+ }
+ /* Where is `this' and newfd now? */
+ fcntl(p[this], F_SETFD, FD_CLOEXEC);
+ fcntl(newfd, F_SETFD, FD_CLOEXEC);
+ pid = do_spawn_nowait(cmd);
+ if (newfd != (*mode == 'r')) {
+ dup2(newfd, *mode == 'r'); /* Return std* back. */
+ close(newfd);
+ }
+ close(p[that]);
+ if (pid == -1) {
+ close(p[this]);
+ return NULL;
+ }
+ if (p[that] < p[this]) {
+ dup2(p[this], p[that]);
+ close(p[this]);
+ p[this] = p[that];
+ }
+ sv = *av_fetch(fdpid,p[this],TRUE);
+ (void)SvUPGRADE(sv,SVt_IV);
+ SvIVX(sv) = pid;
+ forkprocess = pid;
+ return PerlIO_fdopen(p[this], mode);
-#ifdef TRYSHELL
+#else /* USE_POPEN */
+
+ PerlIO *res;
+ SV *sv;
+
+# ifdef TRYSHELL
res = popen(cmd, mode);
-#else
+# else
char *shell = getenv("EMXSHELL");
my_setenv("EMXSHELL", SH_PATH);
res = popen(cmd, mode);
my_setenv("EMXSHELL", shell);
-#endif
+# endif
sv = *av_fetch(fdpid, PerlIO_fileno(res), TRUE);
(void)SvUPGRADE(sv,SVt_IV);
SvIVX(sv) = -1; /* A cooky. */
return res;
+
+#endif /* USE_POPEN */
+
}
/******************************************************************/
}
XSRETURN(1);
}
+typedef APIRET (*PELP)(PSZ path, ULONG type);
+
+APIRET
+ExtLIBPATH(ULONG ord, PSZ path, ULONG type)
+{
+ loadByOrd(ord); /* Guarantied to load or die! */
+ return (*(PELP)ExtFCN[ord])(path, type);
+}
-#define extLibpath(type) \
- (CheckOSError(DosQueryExtLIBPATH(to, ((type) ? END_LIBPATH \
- : BEGIN_LIBPATH))) \
+#define extLibpath(type) \
+ (CheckOSError(ExtLIBPATH(ORD_QUERY_ELP, to, ((type) ? END_LIBPATH \
+ : BEGIN_LIBPATH))) \
? NULL : to )
#define extLibpath_set(p,type) \
- (!CheckOSError(DosSetExtLIBPATH((p), ((type) ? END_LIBPATH \
- : BEGIN_LIBPATH))))
+ (!CheckOSError(ExtLIBPATH(ORD_SET_ELP, (p), ((type) ? END_LIBPATH \
+ : BEGIN_LIBPATH))))
XS(XS_Cwd_extLibpath)
{